c# - Entity Framework 在运行时将模型类映射到表

标签 c# entity-framework-core asp.net-core-2.0

在一个使用 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 元组中包含所有自定义状态,可以将相同的技术应用于包含影响状态的自定义模型的任何上下文。当然,它可以在没有值元组的情况下实现,只是有了它们,GetHashCodeEquals 覆盖更容易实现。实际上,自定义服务可以直接返回包含上下文类型和自定义状态成员值的值元组,而不是 CustomModelCacheKey

关于c# - Entity Framework 在运行时将模型类映射到表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51864015/

相关文章:

asp.net-core - asp.net core 中的 Url.Action

c# - 这是否容易受到注入(inject)攻击

c# - 如何订购应用程序设置

c# - Chilkat C# Crypt2 与 .NET 框架加密

.net-core - 尽管没有进行任何更改,但为什么 EF Core 在每次迁移时都会更新种子 bool 字段?

c# - EF Core 在查询中使用 Let 抛出 "Argument types do not match"异常

c# - 执行线程列表

c# - 无法找到名称为 Pomelo.EntityFrameworkCore.MySql 的提供程序集

asp.net-core - 在构建 WebHost 之前访问托管环境

c# - 从 asp.net core 2.0 中的中间件获取 HttpContext 中的请求正文