如何根据表名在DbContext中选择正确的DbSet

17

假设我有一个DbContext,其中包含以下DbSet:

class Amimals : DbContext
{
    public DbSet<Dog> Dogs { get; set; }
    public DbSet<Cat> Cats { get; set; }
}

在每个EntityTypeConfiguration中,我正在定义每个DbSet的表,例如:

class DogConfig : EntityTypeConfiguration
{
    public DogConfig()
    {
        this.ToTable("DOG_TABLE");
        ...
    }
}

现在,如果我有表名和DbContext,我该如何获取并使用正确的DbSet?

void foo()
{
    string tableName = this.GetTableName();
    using(Animals context = new Animals())
    {
        /* Made up solution */
        DbSet animalContext = context.Where(c => c.TableName == tableName);
        ...
        /* Do something with DbSet */
        ...
    }
}

3个回答

26
你可以通过使用方法DbContext.Set(Type entityType),从DbContext中根据Type获取DbSet。所以如果你有模型类的名称作为字符串,你需要进行一些映射来得到实际的clr类型。
例如:
string tableName = "Cat";
var type = Assembly.GetExecutingAssembly()
        .GetTypes()
        .FirstOrDefault(t => t.Name == tableName);

DbSet catContent;
if(type != null)
    catContent = context.Set(type);

你还可以使用完整的程序集限定名称 Type.GetType(' ... ') 从字符串中获取类型。
如果你能以一种通用的方式存储配置,并使用泛型的 context.Set() 方法,那将更加容易。

好的,这里返回的是EntityTypeConfiguration类。我需要使用DbSet。 有没有一种方法可以在上下文中获取DbSet的实例? - DobleA
1
是的,你可以。这段代码运行良好并返回DbSet的实例。在我的示例中,“tableName”必须与模型类名称匹配。请注意,“tableName”等于“Cat”,因此结果将为DbSet<Cat>。好的,“tableName”听起来有些不清楚,它应该是“c#模型类名称,用于DbContext通用DbSet与此类型表示某个表名”。请分享您的不工作的代码。 - Viktor Bahtev
1
嗯,我不能像这样调用Linq方法到DbSet中:context.Cats.Select(c => c)。我尝试使用AsQueryable(),但仍然不行。 - DobleA
1
http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.set(v=vs.113).aspx说`context.Set(type)`返回一个非泛型的DbSet实例。如果我输入`context.Set<Cat>(),我实际上可以调用返回的DbSet的linq方法。有没有一种方法可以使用<>`的方式? - DobleA
7
顺便提一句,这种方法在 Entity Framework 上运行良好,但是在 Entity Framework Core 上不起作用。对于 EF Core,我发现这个方法非常有用。希望其他人也能找到这条评论有用! - Deadpool
显示剩余2条评论

2

另一种方法如下,对我来说很有效:

Type t = Type.GetType(Assembly.GetExecutingAssembly().GetName().Name + "." + "TableName");
DbSet dbset = dbcontext.Set(t);

错误 CS0411:无法从使用中推断出方法“method”的类型参数。请尝试显式指定类型参数。 - Amir978
@Amir978 您正在使用 Entity Framework Core (EF Core)。问题是关于 Entity Framework(可能是 EF 6)。 - Bamdad

0
在DotNetCore中,我做了类似这样的事情。在这种情况下,最好使用白名单来确保有人不会请求不良实体。
    [HttpGet]
    [Route("entities/{entityName}")]
    public IActionResult GetEntities(string entityName)
    {
        var name = Assembly.GetExecutingAssembly().GetName().Name + ".path.to.your.entity." + entityName;
        Type entityType = Type.GetType(name);
        var results = _myContext
            .GetType()
            .GetMethod("Set")
            .MakeGenericMethod(entityType)
            .Invoke(_myContext, null);
        return Ok(results);
    }

感谢您的回答,我尝试了一下,但是entityType 为空,所以下一行代码会抛出错误:System.Reflection.AmbiguousMatchException 找到了多个匹配项。 - Amir978
@Amir978 只是猜测,但你可能有两个不同命名空间中同名的类。 - Matt
@Amir978 不,问题是因为有两个Set方法。Set<T>()和Set<T>(string)。对我有用的是查询:...GetMethods().First(e => e.Name == "Set" && e.IsGenericMethod) - Michael Mairegger

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