使用SqlSugar进行动态创建和操作表--CRUD

在SqlSugar中动态创建表和进行CRUD操作,可以通过以下步骤实现。这里使用动态对象ExpandoObject)或字典表示数据,并使用动态表名进行操作:

1. 安装SqlSugar

Install-Package SqlSugar

2. 动态创建表与CRUD示例

using SqlSugar;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;

public class DynamicTableService
{
    private readonly SqlSugarClient _db;

    public DynamicTableService(string connectionString)
    {
        _db = new SqlSugarClient(new ConnectionConfig()
        {
            ConnectionString = connectionString,
            DbType = DbType.SqlServer, // 根据数据库修改(支持MySQL、SQLite等)
            IsAutoCloseConnection = true,
        });
        
        // 初始化ORM配置
        _db.Aop.OnLogExecuting = (sql, pars) => Console.WriteLine(sql);
    }

    // 动态创建表(若不存在)
    public void CreateTableIfNotExists(string tableName, List<TableColumn> columns)
    {
        // 生成动态类型(通过反射Emit创建)
        var entityType = DynamicTypeBuilder.CreateType(columns);
        // 使用CodeFirst同步表结构
        _db.CodeFirst.InitTables(entityType); // 自动根据类名建表
        // 如果表名需要自定义(与类名不同),需添加特性 [SugarTable("TableName")]
    }

    // 插入数据
    public int Insert(string tableName, ExpandoObject entity)
    {
        return _db.InsertableByObject(entity).AS(tableName).ExecuteCommand();
    }

    // 批量插入
    public int InsertRange(string tableName, List<ExpandoObject> entities)
    {
        return _db.InsertableByObject(entities).AS(tableName).ExecuteCommand();
    }

    // 更新数据
    public int Update(string tableName, ExpandoObject entity, string primaryKey = "Id")
    {
        dynamic expando = entity;
        var id = ((IDictionary<string, object>)entity)[primaryKey];
        return _db.UpdateableByObject(entity)
            .AS(tableName)
            .WhereColumns(primaryKey, id.ToString())
            .ExecuteCommand();
    }

    // 删除数据(根据主键)
    public int Delete(string tableName, object primaryKeyValue, string primaryKey = "Id")
    {
        return _db.Deleteable<object>()
            .AS(tableName)
            .Where($"{primaryKey} = @id", new { id = primaryKeyValue })
            .ExecuteCommand();
    }

    // 查询所有数据
    public List<ExpandoObject> GetAll(string tableName)
    {
        return _db.Queryable<ExpandoObject>().AS(tableName).ToList();
    }

    // 条件查询
    public List<ExpandoObject> Where(string tableName, string whereSql, object parameters = null)
    {
        return _db.Queryable<ExpandoObject>().AS(tableName).Where(whereSql, parameters).ToList();
    }
}

// 列定义结构
public class TableColumn
{
    public string Name { get; set; }
    public Type Type { get; set; }  // 如:typeof(int), typeof(string)
    public bool IsPrimaryKey { get; set; } = false;
    public bool IsIdentity { get; set; } = false;
}

// 动态类型生成工具(通过反射Emit)
public static class DynamicTypeBuilder
{
    public static Type CreateType(List<TableColumn> columns)
    {
        var typeBuilder = DynamicModule.CreateTypeBuilder();
        
        foreach (var col in columns)
        {
            DynamicModule.CreateProperty(typeBuilder, col.Name, col.Type);
            
            // 添加主键和自增特性
            if (col.IsPrimaryKey)
            {
                typeBuilder.AddSugarPrimaryKey(col.Name, col.IsIdentity);
            }
        }
        
        return typeBuilder.CreateType();
    }
}

// 动态构建模块
public static class DynamicModule
{
    private static readonly System.Reflection.Emit.ModuleBuilder _moduleBuilder;

    static DynamicModule()
    {
        var assemblyName = new System.Reflection.AssemblyName("DynamicTypes");
        var assemblyBuilder = System.Reflection.Emit.AssemblyBuilder.DefineDynamicAssembly(
            assemblyName, System.Reflection.Emit.AssemblyBuilderAccess.Run);
        _moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
    }

    public static System.Reflection.Emit.TypeBuilder CreateTypeBuilder()
    {
        string typeName = "DynamicType_" + Guid.NewGuid().ToString("N");
        return _moduleBuilder.DefineType(typeName, System.Reflection.TypeAttributes.Public);
    }

    public static void CreateProperty(System.Reflection.Emit.TypeBuilder typeBuilder, string name, Type type)
    {
        var fieldBuilder = typeBuilder.DefineField("_" + name, type, System.Reflection.FieldAttributes.Private);
        
        var propertyBuilder = typeBuilder.DefineProperty(
            name,
            System.Reflection.PropertyAttributes.None,
            type,
            Type.EmptyTypes);
        
        var getMethod = typeBuilder.DefineMethod(
            "get_" + name,
            System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.SpecialName,
            type,
            Type.EmptyTypes);
        
        var getIL = getMethod.GetILGenerator();
        getIL.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
        getIL.Emit(System.Reflection.Emit.OpCodes.Ldfld, fieldBuilder);
        getIL.Emit(System.Reflection.Emit.OpCodes.Ret);
        
        var setMethod = typeBuilder.DefineMethod(
            "set_" + name,
            System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.SpecialName,
            null,
            new[] { type });
        
        var setIL = setMethod.GetILGenerator();
        setIL.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
        setIL.Emit(System.Reflection.Emit.OpCodes.Ldarg_1);
        setIL.Emit(System.Reflection.Emit.OpCodes.Stfld, fieldBuilder);
        setIL.Emit(System.Reflection.Emit.OpCodes.Ret);
        
        propertyBuilder.SetGetMethod(getMethod);
        propertyBuilder.SetSetMethod(setMethod);
    }

    public static void AddSugarPrimaryKey(
        this System.Reflection.Emit.TypeBuilder typeBuilder,
        string propertyName,
        bool isIdentity)
    {
        // 为属性添加 [SugarColumn(IsPrimaryKey=true, IsIdentity=true)] 特性
        var attrType = typeof(SugarColumn);
        var ctor = attrType.GetConstructor(new Type[] { });
        var builder = new System.Reflection.Emit.CustomAttributeBuilder(
            ctor, new object[] { }, 
            new[] { typeof(SugarColumn).GetProperty("IsPrimaryKey") },
            new object[] { true },
            new[] { typeof(SugarColumn).GetProperty("IsIdentity") },
            new object[] { isIdentity }
        );
        typeBuilder.DefineProperty(
            propertyName,
            System.Reflection.PropertyAttributes.None,
            null, null)
            .SetCustomAttribute(builder);
    }
}

使用示例

var service = new DynamicTableService("YourConnectionString");

// 定义动态表结构
var columns = new List<TableColumn>
{
    new TableColumn { Name = "Id", Type = typeof(int), IsPrimaryKey = true, IsIdentity = true },
    new TableColumn { Name = "Name", Type = typeof(string) },
    new TableColumn { Name = "Age", Type = typeof(int) }
};

// 创建表(自动根据类名同步表结构)
service.CreateTableIfNotExists("DynamicPerson", columns);

// 插入数据
dynamic data = new ExpandoObject();
data.Name = "Alice";
data.Age = 30;
service.Insert("DynamicPerson", data);

// 查询
var allData = service.GetAll("DynamicPerson");
foreach (dynamic item in allData)
{
    Console.WriteLine($"Id: {item.Id}, Name: {item.Name}");
}

// 条件查询
var adults = service.Where("DynamicPerson", "Age > @age", new { age = 18 });

关键说明

  1. 动态表创建

    • 使用 DynamicTypeBuilder 运行时生成实体类。
    • 通过 db.CodeFirst.InitTables(type) 同步表结构。
  2. 动态CRUD

    • 插入:InsertableByObject + AS(tableName)
    • 查询:Queryable<ExpandoObject>() + AS(tableName)
    • 支持动态条件拼接(Where中使用参数化SQL避免注入)。
  3. 注意事项

    • 不同数据库(如MySQL/SQLite)需修改 DbType
    • 主键自增需在列定义中设置 IsIdentity=true
    • 实际生产环境中建议添加异常处理和事务。
  4. 高级场景

    • 动态修改表结构:使用 db.DbMaintenance 操作DDL语句。
    • 分表分库:结合 SplitTable 功能实现(需额外配置)。

通过这种方式,你可以在SqlSugar中灵活操作动态生成的表结构并执行CRUD操作。

posted @ 2025-07-08 14:24  今天昔水  阅读(148)  评论(0)    收藏  举报