【问题标题】:Work in Progress / Entity Clones正在进行的工作/实体克隆
【发布时间】:2016-06-25 21:47:06
【问题描述】:

我首先使用代码,并且有许多实体要求每个实体都有一个“正在进行中”的版本。传统上,我们通过为所有这些带有前缀“wip”的实体克隆表来实现这种模式。版本。虽然这个系统可以工作,但代码中有很多丑陋之处,我希望使用 Entity Framework 找到一个更简洁、不那么突兀的解决方案。

理想情况下,我会喜欢这样的东西:

using (MyDBContext ctx = new MyDBContext()) {
    Person myPerson = ctx.First(x => x.Name == "frank");
    // Do work with the non "work in progress" entities
}

using (MyWIPContext wipCtx = new MyWIPContext()) {
    Person myPerson = wipCtx.First(x => x.Name == "frank");
    // Do work with the "work in progress" entites
    // If I need to move this entity to non "Work in Progress" maybe do:
    ctx.Attach(myPerson);
    ctx.SaveChanges();   // Where ctx is the non "Work in Progress context"
}

从我的挖掘中,我觉得这可能是可能的。我发现我可以添加一个规则来为“wip”添加前缀。在我的桌子前 (How to Add Table Prefix In Entity Framework Code First Globally?)

还发现了一篇涉及多个架构的帖子 (Entity Framework and multiple schemas) 参考这篇文章 (http://romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first/)

我遇到的一些问题是使用迁移来创建数据库。如果我有多个 DBContext 的迁移开始变得混乱,并且在第二篇文章中它们根本不起作用,因为它们没有为 DBContext 提供一种构建方式,因此迁移失败。

有谁知道实现这种模式的干净方法。我希望它尽可能不突兀。实体不应该知道他们有两个可以坚持的地方(正在进行的工作和真实版本)。我知道我可以通过向实体添加标志来做到这一点,但我觉得还有另一种方法。

【问题讨论】:

  • 您使用的是哪个 EF 版本?
  • 这是一个新项目,所以我可以使用最新最好的
  • 因此,如果您使用 EF6,迁移和多个 dbcontext 的问题将不再存在。您只需要在执行命令时设置“配置”参数。 stackoverflow.com/questions/21537558/…。我在您的方法中看到的问题是关于管理 ID 和 FK,以防您在 WIP 区域创建新实体并使用数据库生成的身份
  • 我很幸运,我不会使用数据库生成的身份,所有实体都有自己的外部密钥。有没有办法将两个 DbContext 合并到 1 个迁移中?都将在同一个数据库中
  • 我认为您不能共享迁移。 IE AddColumn 将包含表名作为参数,因此如果您有不同的表,它将无法工作

标签: c# entity-framework design-patterns entity-framework-6


【解决方案1】:

您可以有 2 个类(LivePersonWipPerson)继承您当前的 Person 类。然后你会告诉 Entity Framework 将每个类映射到不同的表。

EF 配置:

modelBuilder.Entity<LivePerson>()
    .Map(m => m.MapInheritedProperties()
        .ToTable("Persons"));

modelBuilder.Entity<WipPerson>()
    .Map(m => m.MapInheritedProperties()
        .ToTable("WipPersons"));

那么你可以这样做:

// Create Frank
using (var db = new Db())
{
    // Create Frank
    LivePerson frank = new LivePerson { Name = "Frank" };

    // Clone Frank
    WipPerson wipFrank = Clone<LivePerson, WipPerson>(frank);

    // Add to database and save
    db.Persons.Add(frank);
    db.WipPersons.Add(wipFrank);
    db.SaveChanges();
}

// Edit WIP
using (var db = new Db())
{
    var wipFrank = db.WipPersons.First(/*Todo: Use query*/);

    wipFrank.Notes = "Okay";

    db.SaveChanges();
}

这将为您提供相同内容的副本,但在单独的表格中。但是有一个新的复杂性:您必须能够将 Person 从一种类型克隆到另一种类型。

我用了这个方法:

private static TOut Clone<TIn, TOut>(TIn obj)
{
    // using Newtonsoft.Json;
    return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(obj));
}

如果你的人足够简单,可以被克隆,我认为这个解决方案可能会奏效...... 或者至少您可以专注于根据您的需要将克隆从一种类型改进为另一种类型。

此解决方案还允许您更进一步,向WipPerson 类添加一些属性,以跟踪克隆的创建时间、创建者、最后编辑者以及LivePerson 克隆的来源制作等等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 2012-07-22
    • 2016-03-17
    相关资源
    最近更新 更多