You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Entity Framework中如何根据字符串实体名动态操作DbSet?

解决方案:根据字符串名称动态操作Entity Framework实体

问题描述

我是C#和Entity Framework的新手,需要根据检查和条件向表中插入记录,但不知道执行增改操作的实体类型。

可以直接指定实体类型添加记录:

await _dbContext.Set<UserLogs>().AddAsync((UserLogs)ObjectChanges);
await _dbContext.Set<PageLogs>().AddAsync((PageLogs)ObjectChanges);

但场景中只有实体的字符串名称("UserLogs"、"PageLogs"),无法直接传入_dbContext.Set<>。我尝试通过以下代码获取实体类型,但没找到可行的动态操作方案:

var TEntity = _dbContext.Model.GetEntityTypes()
    .First(x => x.Name.Contains("UserLogs"));

更新后的尝试代码(存在语法错误):

Type LogType = Type.GetType($"UserLogs");
if (LogType != null)
{
    var LogObject = Activator.CreateInstance(LogType);
    if (LogObject != null)
    {
        foreach (PropertyInfo property in LogType.GetProperties())
        {
            if (property.CanWrite)
            {
                if (property.PropertyType == typeof(string))
                {
                    property.SetValue(LogObject, Convert.ToString(Entity.GetType().GetProperty(property.Name)?.GetValue(Entity)));
                }
            }
        }
        var TEntity = _dbContext.Model.GetEntityTypes().First(x => x.Name.Contains("UserLogs"));

        await _dbContext.Set<$"UserLogs">().AddAsync(("UserLogs")LogObject);
    }
}

可行解决方案

要实现动态获取DbSet并插入实体,需要结合反射和EF的非泛型方法:

步骤1:正确获取实体Type

Type.GetType("UserLogs")可能因为缺少命名空间导致返回null,推荐从DbContext的Model中直接获取:

string entityName = "UserLogs";
Type entityType = _dbContext.Model.GetEntityTypes()
    .First(t => t.ClrType.Name == entityName)
    .ClrType;

步骤2:创建实体实例并赋值

保留属性复制逻辑,同时兼容非字符串类型的赋值:

object entityInstance = Activator.CreateInstance(entityType);
// 从数据源对象复制属性值(这里假设Entity是数据源)
foreach (PropertyInfo prop in entityType.GetProperties())
{
    if (prop.CanWrite)
    {
        PropertyInfo sourceProp = Entity.GetType().GetProperty(prop.Name);
        if (sourceProp != null)
        {
            object value = sourceProp.GetValue(Entity);
            prop.SetValue(entityInstance, value);
        }
    }
}

步骤3:动态获取DbSet并添加记录

使用EF的非泛型Set(Type)方法,结合反射调用AddAsync:

// 获取非泛型DbSet
var dbSet = _dbContext.Set(entityType);
// 反射获取并调用AddAsync方法
MethodInfo addAsyncMethod = dbSet.GetType().GetMethod("AddAsync", new[] { entityType });
if (addAsyncMethod != null)
{
    await (Task)addAsyncMethod.Invoke(dbSet, new[] { entityInstance });
    await _dbContext.SaveChangesAsync();
}

完整示例代码

public async Task AddDynamicLog(string entityName, object sourceEntity)
{
    // 1. 获取实体Type
    Type entityType = _dbContext.Model.GetEntityTypes()
        .First(t => t.ClrType.Name == entityName)
        .ClrType;

    // 2. 创建实体实例并复制属性
    object entityInstance = Activator.CreateInstance(entityType);
    foreach (PropertyInfo prop in entityType.GetProperties())
    {
        if (prop.CanWrite)
        {
            PropertyInfo sourceProp = sourceEntity.GetType().GetProperty(prop.Name);
            if (sourceProp != null)
            {
                object value = sourceProp.GetValue(sourceEntity);
                prop.SetValue(entityInstance, value);
            }
        }
    }

    // 3. 动态添加并保存
    var dbSet = _dbContext.Set(entityType);
    MethodInfo addAsyncMethod = dbSet.GetType().GetMethod("AddAsync", new[] { entityType });
    if (addAsyncMethod != null)
    {
        await (Task)addAsyncMethod.Invoke(dbSet, new[] { entityInstance });
        await _dbContext.SaveChangesAsync();
    }
}

// 调用示例
await AddDynamicLog("UserLogs", ObjectChanges);
await AddDynamicLog("PageLogs", ObjectChanges);

注意事项

  • 实体名称建议精确匹配,避免Contains模糊匹配导致的多实体冲突问题。
  • 如果实体有带参数的构造函数,需要改用Activator.CreateInstance(entityType, 参数数组)初始化实例。
  • 反射操作存在一定性能开销,高频场景下建议缓存实体Type和AddAsync方法的引用。

内容的提问来源于stack exchange,提问作者Alisbha Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 21:32:46