在 EntityFramework Code First 迁移中覆盖“dbo”模式名称

Posted

技术标签:

【中文标题】在 EntityFramework Code First 迁移中覆盖“dbo”模式名称【英文标题】:Override "dbo" schema name in EntityFramework Code First Migrations 【发布时间】:2017-12-02 07:03:43 【问题描述】:

我正在尝试使用 EntityFramework Codefirst 和 Oracle 数据库创建一个独立于模式的模型,但 EF 将迁移 dbo 用作模式的默认值。 我在我的 DBContext 上覆盖了 OnModelCreating 方法来解决这个问题,并在 connectionString 中使用用户来代替

protected override void OnModelCreating(DbModelBuilder modelBuilder)

   base.OnModelCreating(modelBuilder);
   modelBuilder.HasDefaultSchema(string.Empty);

问题是 __MigrationHistory 忽略了这个默认架构,并且在运行第一次迁移时出现此错误:

ORA-01918: 用户 'dbo' 不存在

尝试this msdn entry 自定义此表的架构。

CustomHistoryContext:

public class CustomHistoryContext : HistoryContext

    public CustomHistoryContext(DbConnection dbConnection, string defaultSchema)
            : base(dbConnection, defaultSchema) 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        base.OnModelCreating(modelBuilder);

        modelBuilder.HasDefaultSchema(String.Empty);
    

和 DBConfiguration:

public sealed class Configuration :
        DbMigrationsConfiguration<Model.MyDbContext>

    public Configuration()
    
        AutomaticMigrationsEnabled = false;
        SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
                                 (connection, defaultSchema) => new CustomHistoryContext(connection, defaultSchema));
    

    protected override void Seed(Model.Model1 context)
    
    

并且在第一次迁移时工作正常。但是当我修改我的实体模型并尝试使用add-migration 命令反映此更改时,我收到以下错误:

无法生成显式迁移,因为以下原因 显式迁移待定:[201706281804589_initial, 201706281810218_pp2]。在之前应用挂起的显式迁移 尝试生成新的显式迁移。

看起来 EF 丢失了,此时无法找到迁移历史记录。

当我在 Configuration 中评论 SetHistoryContextFactory 指令时,它适用于后续的 add-migration 命令,但是当我想从头开始运行所有迁移(例如部署)时,这种解决方法还不够。

有谁知道我是否可以很好地完成此任务,或者是否有更好的解决方法?

【问题讨论】:

您使用的是哪个 Oracle 提供商?可能是 Oracle 提供程序没有实现此功能的问题。如果您可以快速访问它,也许可以使用 SQL Server 快速尝试一下,看看结果是否相同?此外,不确定是否提供 string.Empty 架构使其默认为嵌入式默认值 (dbo)。 嗨@MichaelWeinand,感谢您的快速评论。我正在使用 Nuget 包中的 Oracle.ManagedDataAccess.EntityFramework v12.1.2400。尝试使用 SQL Server,但 string.Empty 用于 MyDBcontext 架构名称和 sql 脚本是可以的,但对于 CustomHistoryContext 生成的 sql 插入历史中的第一个迁移是:INSERT [CodeFirstDatabase].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])... 注意 CodeFirstDatabase 架构名称 不幸的是,SQL Server 和 Oracle 在架构是什么以及如何与之交互方面的概念略有不同。我猜 [CodeFirstDatabase] 名称是一个内置的默认值,如果你传入 string.Empty 就会使用它。您实际上想将其设置为什么?即使在 Oracle 中,我也不确定您是否真的不能提供模式名称? 一个简化的教程可以在这里找到:oracle.com/webfolder/technetwork/tutorials/obe/db/dotnet/… @oskr 嘿,我也有同样的问题。以下答案是否为您解决了问题,或者您是否找到了其他解决方案 - 干杯 【参考方案1】:

转到 Migrations -> Configuration.cs 和下面提到的代码。这个修复对我有用!

class Configuration : DbMigrationsConfiguration<CodeFirstOracleProject.Context>

    public Configuration()
    
        AutomaticMigrationsEnabled = false;
        var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
        SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
                                 (dbc, schema) => historyContextFactory.Invoke(dbc, "YourSchemaName"));
    

【讨论】:

【参考方案2】:

再次尝试运行Enable-Migrations -force。然后运行 ​​Add-Migration SomeDescription –IgnoreChanges。之后,运行“Update-Database - Verbose”。这对我有用

【讨论】:

【参考方案3】:

我在 Oracle 的 Configuration : DbMigrationsConfiguration 类中成功尝试了以下操作,以便将历史模式更改为“测试”:

var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
                         (dbc, schema) => historyContextFactory.Invoke(dbc, "Test"));

所以基本上,我没有尝试使用未更改的默认架构注册自定义历史上下文,而是尝试使用更改的默认架构注册默认历史上下文。

结果:当我运行Update-Database -Script 时,生成的脚本包含用于创建__MigrationHistory 表以及插入新历史值的新模式:

create table "Test"."__MigrationHistory"
    -- ...

insert into "Test"."__MigrationHistory"("MigrationId", "ContextKey", "Model", "ProductVersion") ...

但是,让我们非常清楚:我只是尝试了我期望通过直觉工作的东西,它确实对我有用。我没有找到任何可靠的文档来支持此解决方案。

【讨论】:

【参考方案4】:

打开 Migrations -> Configuration.cs 并添加

 public Configuration()
    
        AutomaticMigrationsEnabled = false;            
        var historyContextFactory = GetHistoryContextFactory("Oracle.ManagedDataAccess.Client");
        SetHistoryContextFactory("Oracle.ManagedDataAccess.Client",
                                 (dbc, schema) => historyContextFactory.Invoke(dbc, "your_schema_name_hear"));

    

【讨论】:

以上是关于在 EntityFramework Code First 迁移中覆盖“dbo”模式名称的主要内容,如果未能解决你的问题,请参考以下文章

EntityFramework Code-First 简易教程-------领域类配置之DataAnnotations

EntityFramework Code First 模式下使用数据迁移

EntityFramework Reverse POCO Code First 生成器

在 EntityFramework Code First 迁移中覆盖“dbo”模式名称

EntityFramework Code-First 简易教程-------领域类配置之Fluent API

EntityFramework Code-First 简易教程-------一对多