znlgis 博客

GIS开发与技术分享

第十七章:数据库与项目管理

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集成为多人协同设计场景提供了实时通信能力。


上一章第十六章:命令与操作系统

下一章第十八章:标注与文本系统