第十七章:数据库与项目管理
17.1 数据库模块概述
17.1.1 数据库相关模块
LightCAD包含两个数据库相关的模块:
| 模块 | 说明 |
|---|---|
| LightCAD.DBHelper | 数据库帮助工具,提供通用的数据库操作接口 |
| LightCAD.DBUtility | 数据库工具类,封装具体的数据库访问逻辑 |
17.1.2 项目管理模块
| 模块 | 说明 |
|---|---|
| LightCAD.PrjManager | 项目管理器,管理项目生命周期 |
| LightCAD.LocalSolution | 本地工作空间管理 |
17.2 数据库帮助工具(DBHelper)
17.2.1 数据库连接管理
public class DBHelper
{
private string connectionString;
public DBHelper(string connectionString)
{
this.connectionString = connectionString;
}
/// <summary>
/// 执行查询,返回数据表
/// </summary>
public DataTable ExecuteQuery(string sql, params DbParameter[] parameters)
{
using var connection = CreateConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = sql;
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
using var adapter = CreateDataAdapter(command);
var table = new DataTable();
adapter.Fill(table);
return table;
}
/// <summary>
/// 执行非查询命令(INSERT、UPDATE、DELETE)
/// </summary>
public int ExecuteNonQuery(string sql, params DbParameter[] parameters)
{
using var connection = CreateConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = sql;
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
return command.ExecuteNonQuery();
}
/// <summary>
/// 执行标量查询
/// </summary>
public object ExecuteScalar(string sql, params DbParameter[] parameters)
{
using var connection = CreateConnection();
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = sql;
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
return command.ExecuteScalar();
}
/// <summary>
/// 事务执行
/// </summary>
public void ExecuteInTransaction(Action<DbConnection, DbTransaction> action)
{
using var connection = CreateConnection();
connection.Open();
using var transaction = connection.BeginTransaction();
try
{
action(connection, transaction);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
17.2.2 数据库工具类
public class DBUtility
{
/// <summary>
/// 保存实体到数据库
/// </summary>
public void SaveEntity(LcEntity entity, DBHelper db)
{
var sql = @"INSERT INTO Entities
(Handle, Guid, TypeName, LayerName, ColorR, ColorG, ColorB,
LineType, LineWeight, IsVisible, GeometryData)
VALUES
(@Handle, @Guid, @TypeName, @LayerName, @ColorR, @ColorG, @ColorB,
@LineType, @LineWeight, @IsVisible, @GeometryData)
ON CONFLICT(Handle) DO UPDATE SET
GeometryData = @GeometryData";
db.ExecuteNonQuery(sql,
new DbParameter("@Handle", entity.Handle),
new DbParameter("@Guid", entity.Guid.ToString()),
new DbParameter("@TypeName", entity.TypeName),
new DbParameter("@LayerName", entity.LayerName),
new DbParameter("@ColorR", entity.Color.R),
new DbParameter("@ColorG", entity.Color.G),
new DbParameter("@ColorB", entity.Color.B),
new DbParameter("@LineType", entity.LineType ?? ""),
new DbParameter("@LineWeight", entity.LineWeight),
new DbParameter("@IsVisible", entity.IsVisible),
new DbParameter("@GeometryData", SerializeGeometry(entity))
);
}
/// <summary>
/// 从数据库加载实体
/// </summary>
public List<LcEntity> LoadEntities(DBHelper db)
{
var sql = "SELECT * FROM Entities WHERE IsVisible = 1";
var table = db.ExecuteQuery(sql);
var entities = new List<LcEntity>();
foreach (DataRow row in table.Rows)
{
var entity = DeserializeEntity(row);
if (entity != null)
{
entities.Add(entity);
}
}
return entities;
}
}
17.3 项目管理器(PrjManager)
17.3.1 项目结构
public class Project
{
/// <summary>
/// 项目唯一标识
/// </summary>
public LcGuid Guid { get; set; }
/// <summary>
/// 项目名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 项目描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 项目路径
/// </summary>
public string ProjectPath { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedAt { get; set; }
/// <summary>
/// 最后修改时间
/// </summary>
public DateTime ModifiedAt { get; set; }
/// <summary>
/// 项目文件列表
/// </summary>
public List<ProjectFile> Files { get; set; } = new();
/// <summary>
/// 项目设置
/// </summary>
public ProjectSettings Settings { get; set; } = new();
}
public class ProjectFile
{
public string FileName { get; set; }
public string RelativePath { get; set; }
public string FileType { get; set; }
public DateTime ModifiedAt { get; set; }
public long FileSize { get; set; }
}
public class ProjectSettings
{
public LengthUnit DefaultUnit { get; set; } = LengthUnit.Millimeter;
public double DefaultScale { get; set; } = 1.0;
public string DefaultFont { get; set; } = "SimSun";
public string DefaultLayer { get; set; } = "0";
}
17.3.2 项目管理器
public class PrjManager
{
private Project currentProject;
private string projectRoot;
/// <summary>
/// 当前项目
/// </summary>
public Project CurrentProject => currentProject;
/// <summary>
/// 创建新项目
/// </summary>
public Project CreateProject(string name, string path)
{
var project = new Project
{
Guid = LcGuid.NewGuid(),
Name = name,
ProjectPath = path,
CreatedAt = DateTime.Now,
ModifiedAt = DateTime.Now
};
// 创建项目目录结构
Directory.CreateDirectory(path);
Directory.CreateDirectory(Path.Combine(path, "Drawings"));
Directory.CreateDirectory(Path.Combine(path, "Models"));
Directory.CreateDirectory(Path.Combine(path, "Templates"));
Directory.CreateDirectory(Path.Combine(path, "Output"));
// 保存项目文件
SaveProjectFile(project);
currentProject = project;
return project;
}
/// <summary>
/// 打开项目
/// </summary>
public Project OpenProject(string projectFilePath)
{
var json = File.ReadAllText(projectFilePath);
currentProject = JsonSerializer.Deserialize<Project>(json);
projectRoot = Path.GetDirectoryName(projectFilePath);
return currentProject;
}
/// <summary>
/// 保存项目
/// </summary>
public void SaveProject()
{
if (currentProject == null) return;
currentProject.ModifiedAt = DateTime.Now;
SaveProjectFile(currentProject);
}
/// <summary>
/// 添加文件到项目
/// </summary>
public void AddFile(string filePath)
{
if (currentProject == null) return;
var relativePath = Path.GetRelativePath(
currentProject.ProjectPath, filePath);
currentProject.Files.Add(new ProjectFile
{
FileName = Path.GetFileName(filePath),
RelativePath = relativePath,
FileType = Path.GetExtension(filePath),
ModifiedAt = File.GetLastWriteTime(filePath),
FileSize = new FileInfo(filePath).Length
});
SaveProject();
}
private void SaveProjectFile(Project project)
{
var json = JsonSerializer.Serialize(project,
new JsonSerializerOptions { WriteIndented = true });
var filePath = Path.Combine(
project.ProjectPath, $"{project.Name}.lcproj");
File.WriteAllText(filePath, json);
}
}
17.4 本地工作空间(LocalSolution)
17.4.1 工作空间管理
public class LocalSolution
{
/// <summary>
/// 工作空间根目录
/// </summary>
public string WorkspacePath { get; set; }
/// <summary>
/// 最近打开的项目列表
/// </summary>
public List<RecentProject> RecentProjects { get; set; } = new();
/// <summary>
/// 用户偏好设置
/// </summary>
public UserPreferences Preferences { get; set; } = new();
/// <summary>
/// 初始化工作空间
/// </summary>
public void Initialize(string basePath)
{
WorkspacePath = basePath;
if (!Directory.Exists(basePath))
{
Directory.CreateDirectory(basePath);
}
LoadPreferences();
LoadRecentProjects();
}
/// <summary>
/// 记录最近打开的项目
/// </summary>
public void AddRecentProject(string projectPath)
{
RecentProjects.RemoveAll(p => p.Path == projectPath);
RecentProjects.Insert(0, new RecentProject
{
Path = projectPath,
LastOpened = DateTime.Now
});
// 只保留最近10个
if (RecentProjects.Count > 10)
{
RecentProjects = RecentProjects.Take(10).ToList();
}
SaveRecentProjects();
}
}
public class RecentProject
{
public string Path { get; set; }
public DateTime LastOpened { get; set; }
public string Name => System.IO.Path.GetFileNameWithoutExtension(Path);
}
public class UserPreferences
{
public string Theme { get; set; } = "Light";
public string Language { get; set; } = "zh-CN";
public int AutoSaveInterval { get; set; } = 300; // 秒
public bool ShowStartPage { get; set; } = true;
public int MaxUndoLevels { get; set; } = 100;
public double DefaultSnapTolerance { get; set; } = 10;
}
17.5 SignalR实时通信
17.5.1 SignalR集成
LightCAD通过SignalR实现客户端与服务端之间的实时通信,支持协同设计场景:
public class CollaborationClient
{
private HubConnection hubConnection;
/// <summary>
/// 连接到协作服务器
/// </summary>
public async Task ConnectAsync(string serverUrl, string projectId)
{
hubConnection = new HubConnectionBuilder()
.WithUrl($"{serverUrl}/collaboration?projectId={projectId}")
.WithAutomaticReconnect()
.Build();
// 注册事件处理
hubConnection.On<string, string>("EntityChanged",
OnEntityChanged);
hubConnection.On<string, string>("EntityAdded",
OnEntityAdded);
hubConnection.On<string>("EntityDeleted",
OnEntityDeleted);
hubConnection.On<string, string>("UserJoined",
OnUserJoined);
hubConnection.On<string>("UserLeft",
OnUserLeft);
await hubConnection.StartAsync();
}
/// <summary>
/// 通知实体变更
/// </summary>
public async Task NotifyEntityChanged(LcEntity entity)
{
if (hubConnection?.State == HubConnectionState.Connected)
{
var entityData = SerializeEntity(entity);
await hubConnection.InvokeAsync("EntityChanged",
entity.Handle.ToString(), entityData);
}
}
/// <summary>
/// 通知添加实体
/// </summary>
public async Task NotifyEntityAdded(LcEntity entity)
{
if (hubConnection?.State == HubConnectionState.Connected)
{
var entityData = SerializeEntity(entity);
await hubConnection.InvokeAsync("EntityAdded",
entity.Handle.ToString(), entityData);
}
}
private void OnEntityChanged(string handle, string data)
{
// 接收其他用户的实体变更
var entity = DeserializeEntity(data);
DocumentManager.Current.UpdateEntity(long.Parse(handle), entity);
}
private void OnEntityAdded(string handle, string data)
{
var entity = DeserializeEntity(data);
DocumentManager.Current.AddEntity(entity);
}
private void OnEntityDeleted(string handle)
{
DocumentManager.Current.RemoveEntity(long.Parse(handle));
}
}
17.6 本章小结
本章介绍了LightCAD的数据库操作和项目管理功能。DBHelper和DBUtility提供了通用的数据库访问能力,支持实体数据的持久化存储。PrjManager实现了完整的项目生命周期管理,包括创建、打开、保存项目以及文件组织。LocalSolution管理本地工作空间和用户偏好设置。SignalR集成为多人协同设计场景提供了实时通信能力。
上一章:第十六章:命令与操作系统
下一章:第十八章:标注与文本系统