【问题标题】:Entity Framework (MySQL) - move data from one database to another using two dbcontexts实体框架 (MySQL) - 使用两个 dbcontexts 将数据从一个数据库移动到另一个数据库
【发布时间】:2018-07-04 07:47:16
【问题描述】:

使用 Entity Framework 6 和 MySQL,我正在尝试将数据从“生产”数据库表存档到“存档”数据库。我为每个数据库创建了两个 DBContext。每个数据库都有相同的架构。

我可以使用以下代码将整个数据表从生产数据库移动到存档数据库:

using (MyDBContext archiveContext = 
MyDBContext.CreateEntitiesForSpecificDatabaseName("archive_db"))
using (MyDBContext prodContext = 
MyDBContext.CreateEntitiesForSpecificDatabaseName("prod_db"))
{
    if(prodContext.myTable.Any())
    {
        archiveContext.myTable.AddRange(prodContext.myTable.AsNoTracking());
        archiveContext.SaveChanges();
    }  
}

但是我不想归档整个表,我只想归档某个日期之前的数据,所以我尝试了以下方法:

using (MyDBContext archiveContext = 
MyDBContext.CreateEntitiesForSpecificDatabaseName("archive_db"))
using (MyDBContext prodContext = 
MyDBContext.CreateEntitiesForSpecificDatabaseName("prod_db"))
{
    IQueryable<myTable> dataToArchive =
      from mt in prodContext.myTable
      where mt.date < DateTimeSixMonths
      select mt;

     archiveContext.myTable.AddRange(dataToArchive);
     archiveContext.SaveChanges();
}       

但我无法绕过运行此程序时遇到的异常:

System.InvalidOperationException: '一个实体对象不能 被多个 IEntityChangeTracker 实例引用。'

它出现在这一行:

archiveContext.myTable.AddRange(dataToArchive); 

是否有可能以某种方式从“dataToArchive”中删除跟踪

【问题讨论】:

    标签: mysql .net entity-framework


    【解决方案1】:

    您是否尝试在检索数据后处理第一个 DataContext?像这样的:

    List<myTable> dataToArchive;
    
    using (MyDBContext prodContext = 
            MyDBContext.CreateEntitiesForSpecificDatabaseName("prod_db"))
    {
    
        dataToArchive = (from mt in prodContext.myTable
            where mt.date < DateTimeSixMonths
            select mt).ToList();
    }
    
    using (MyDBContext archiveContext = 
        MyDBContext.CreateEntitiesForSpecificDatabaseName("archive_db"))
    {
        archiveContext.myTable.AddRange(dataToArchive);
        archiveContext.SaveChanges();
    }
    

    【讨论】:

    • 谢谢,处理第一个 DataContext 还可以防止 IEntityChangeTracker 异常并允许插入到存档表中,但是在创建新主键时我仍然遇到同样的问题,所以决定不使用 2 DBContexts最后。
    【解决方案2】:

    使用 EF 管理归档数据并不理想,对于中低数据量或可分离分区(即 3-6 个月的分区大小),使用插入选择 + 删除可以更好地在数据库级别提供类似的服务可以在数据库之间移动。

    要使用 EF 执行此操作(仅推荐用于小型和非复杂域模型),您应该能够通过在读取上下文中禁用代理生成来完成此操作,加载数据 AsNoTracking,然后将其添加到新的上下文数据库集。此示例不处理关联实体,或从 prod DbSet 中删除。

    using (MyDBContext prodContext = 
            MyDBContext.CreateEntitiesForSpecificDatabaseName("prod_db"))
    {
        prodContext.Configuration.ProxyCreationEnabled = false;
        dataToArchive = prodContext.myTable.AsNoTracking()
            .Where(mt => mt.Date < DateTimeSixMonths);
    
    
        using (MyDBContext archiveContext = 
            MyDBContext.CreateEntitiesForSpecificDatabaseName("archive_db"))
        {
            archiveContext.myTable.AddRange(dataToArchive);
            archiveContext.SaveChanges();
        }
    }
    

    【讨论】:

    • 感谢您提出 EF 的替代方案。我开始认为 EF 方法过于复杂,但它似乎应该是可能的。上述关于禁用代理生成的建议有效,但后来我遇到了一个问题,即插入具有新主键的存档数据库而不是生产表的确切存档。我使用插入选择和删除恢复为更简单的归档解决方案。
    • 是的,要解决这个问题,需要在没有标识/默认值的情况下设置存档数据库,然后您需要使用 DatabaseGeneratedOption 设置为 None 的实体定义。这可能意味着为 prod 提供 2x 实体定义和/或专用 DbContext 以服务于存档过程。比它可能的价值更多的混乱。 :)
    猜你喜欢
    • 2014-05-28
    • 2014-06-20
    • 2012-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多