在一个使用 ASP.NET Core 2.0 和 Entity Framework 的项目中,我试图将一个已知的表架构(编码到类 MyTableClass
中)映射到一个未知的表名。此表名由用户在运行时指定,因此这是在 Context 类的 OnModelCreating
方法之外完成的。有没有办法做类似下面的伪代码:
void OnUserEnteredTableNameFromUI(string tableName)
{
var modelBuilder = new ModelBuilder(???); // how?
modelBuilder.Entity<MyTableClass>().ToTable(tableName);
// how to get a ref to DbSet<MyTableClass> myTable from here?
}
最佳答案
由于这是一个有趣的问题,可能会帮助其他需要一些动态模型构建的人,所以这里是如何实现它的。
假设我们有一个自定义上下文,其中包含通过构造函数提供的自定义表名(正如 Gert Arnold 在另一个答案中所建议的那样):
public class CustomDbContext : DbContext
{
// …
private string customTableName;
public string CustomTableName => customTableName ?? "DefaultCustomTableName";
}
我们在 OnModelCreating
中使用它(它应该在那里,目前没有其他简单的方法可以使用预定义的约定集创建模型):
modelBuilder.Entity<CustomEntity>().ToTable(CustomTableName);
唯一的问题是,默认情况下,OnModelCreating
每个上下文类型只调用一次并被缓存。幸运的是,EF Core 构建在(可替换的)服务架构之上。负责模型缓存的服务接口(interface)是IModelCacheKeyFactory
:
Creates keys that uniquely identifies the model for a given context. This is used to store and lookup a cached model for a given context.
只有一个方法
object Create(DbContext context)
返回的对象GetHashCode
/Equals
方法用于识别传递的上下文实例。默认的 EF Core 服务实现返回一个比较上下文类型的对象。
为了使自定义上下文模型正常工作,我们需要将其替换为自定义服务,该服务也会比较自定义状态(在本例中为 CustomTableName
)。实现可能是这样的(使用 C#7.0 值元组):
class CustomModelCacheKeyFactory : IModelCacheKeyFactory
{
public object Create(DbContext context) => new CustomModelCacheKey(context);
}
class CustomModelCacheKey
{
(Type ContextType, string CustomTableName) key;
public CustomModelCacheKey(DbContext context)
{
key.ContextType = context.GetType();
key.CustomTableName = (context as CustomDbContext)?.CustomTableName;
}
public override int GetHashCode() => key.GetHashCode();
public override bool Equals(object obj) => obj is CustomModelCacheKey other && key.Equals(other.key);
}
唯一剩下的就是用自定义替换现有服务。它可以在 OnConfiguring
override 中完成:
optionsBuilder.ReplaceService<IModelCacheKeyFactory, CustomModelCacheKeyFactory>();
仅此而已。每当您使用不同的 CustomTableName
创建上下文时,EF Core 都会创建一个新模型并将 CustomEntity
映射到该表。
通过在 CustomModelCacheKey.key
元组中包含所有自定义状态,可以将相同的技术应用于包含影响状态的自定义模型的任何上下文。当然,它可以在没有值元组的情况下实现,只是有了它们,GetHashCode
和 Equals
覆盖更容易实现。实际上,自定义服务可以直接返回包含上下文类型和自定义状态成员值的值元组,而不是 CustomModelCacheKey
。
关于c# - Entity Framework 在运行时将模型类映射到表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51864015/