Entity Framework Core中的动态DbSet

8
string tableName = "TblStudents";
Dictionary<string, Type> myDictionary = new Dictionary<string, Type>()
{
    { "TblStudents", typeof(TblStudent) },
    { "TblTeachers", typeof(TblTeacher) }
};

// Context always same
DBContext dbContext = new DBContext();
DbSet dbSet = dbContext.Set(myDictionary[tableName]);

上面的代码来自于这个帖子,我可以动态使用DbSet。如何在Entity Framework Core中实现这个功能?
我在这里遇到了一个错误。
DbSet dbSet = dbContext.Set(myDictionary[tableName]);

似乎新版本中Set方法已经发生了变化。 感谢您的帮助。
2个回答

7

如果你正在尝试通过 TEntity 获取 DbSet<TEntity>,请使用以下方法:

var dbSet = dbContext.Set<TEntity>();

如果您想基于字符串名称和字典调用该方法,您需要使用反射。

EF Core似乎没有非泛型的DbSet,因此您需要使用其中一个非泛型接口,例如IQueryable,并且如果您坚持使用字典映射路线,则应包括一个Func,以便您可以调用它来获取IQueryable而不仅仅是类型。例如:

var myDictionary = new Dictionary<string, Func<DbContext, IQueryable>>()
{
    { "TblStudents", ( DbContext context ) => context.Set<TblStudent>() }
};

var dbSet = myDictionary[ "TblStudents" ].Invoke( dbContext );

1
谢谢您的回答。现在如果我对dbSet进行for循环,由于它是IQueryable类型,我无法获取dbSet内部的属性。 我该如何解决这个问题? - bbusdriver
1
获取哪个属性?如果 IQueryable 不能提供您所需的内容,请使用提供该内容的接口。我不确定您想要实现什么。 - Moho
1
如果我想使用.Add.Remove,看起来这两个方法都不属于任何接口...希望我是错的! - bunjeeb

0

DbContext.SetDbContext.Set(string name) 是 EF Core 中唯一可用的函数。根据我所了解的,DbContext.Set(Type) 适用于 Framework。了解这一限制,我们将能够触发它。

public List<Type> FetchDbSetTypes()
{
    var properties = dbContext.GetType().GetProperties();
    var dbSets = new List<Type>();
    foreach (var property in properties)
    {
        var propertyType = property.PropertyType;
        if(propertyType.IsGenericType && propertyType.Name.ToLower().Contains("dbset"))
        {
            Type dbSetType = propertyType.GenericTypeArguments[0]; //point of interest here
            dbSets.Add(dbSetType);
        }
    }
    return dbSets;
}

现在我们拥有了DBSets定义的强类型列表。接下来,我们需要根据添加的类型欺骗集合。唯一的方法是将该类型的对象作为参数传递。
这需要使用反射,InternalDbSet<>,DBContext和动态
List<Type> dbsetTypes = FetchDbSetTypes();
dbsetTypes.ForEach(async dbsetType =>
{
    try
    {
        Type myType = typeof(InternalDbSet<>).MakeGenericType(dbsetType);
        //instance is only used to spoof the binding
        dynamic instance = Activator.CreateInstance(myType, context, dbsetType.Name);
        var test = await FetchFromTable(instance, 0, 10);
    }
    catch(Exception)
    {
        //might fail due to other models
    }
});

然后我们调用涉及DbSet的通用方法

public async Task<List<T>> FetchFromTable<T>(DbSet<T> _, int skip = 0, int fetchSize = 10000) where T : class
{
    //DbSet<T> parameter is not needed - it will throw an Exception
    return await dbContext.Set<T>().Skip(skip).Take(fetchSize).ToListAsync();
}

注意:确保您的 DbContext 属性具有 getters


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接