参考另一个上下文中的实体创建新实体

时间:2019-08-01 14:21:08

标签: entity-framework ef-migrations

我有2个项目 PRJ1 PRJ2 ,它们使用自己的数据库 DB1 DB2 。每个数据库都使用EF代码优先迁移。

  • PRJ1 用于管理产品库存(已经存在4年了。)
  • PRJ2 用于订单(全新项目仍在开发中)

现在让我们仅讨论第二个项目。在我的项目 PRJ2 中,我需要访问其他数据库 DB1 中的数据。所以我需要订购产品。

这是到目前为止我获得的 PRJ2 请注意,我定义了2个不同的上下文。

// Context for accessing entities in DB1
public class DB1Context : DbContext
{
    static DB1Context()
    {
        Database.SetInitializer<DB1Context>(null);
    }
    public DbSet<Product> Products { get; set; }
}

// Context for accessing entities in DB2
public class DB2Context : DbContext
{
    static DB2Context()
    {
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<DB2Context, DAL.Migrations.Configuration>());
    }
    public DbSet<Anything> Anythings { get; set; }
    public DbSet<Order> Orders { get; set; }
}

行之有效的:我可以从DB1Context(产品)或DB2Context(任何内容)中查询数据。

尚无法解决的问题:创建我的订单实体。

// My Orders entity
public class Orders
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; }

    public virtual Product Product { get; set; }
}

位于DB2Context中的该实体引用了Product实体,它是DB1Context的一部分。

现在的问题是,一旦我在上下文DbSet<Order>中添加该实体,我就会看到有一个迁移正在等待产品。此迁移用于在我的DB2Context中创建产品。那不是我想要的该实体已经存在于DB1Context中。看来我无法创建从其他上下文引用产品的这个Order实体。

您可以确认吗?我错过了什么吗?否则最好的选择是什么?

2 个答案:

答案 0 :(得分:0)

我认为您无法使用Entity Framework做到这一点。

该问题看起来像是No-SQL数据库的问题。当您拥有多个这样的数据库时,您必须控制所有数据库的所有CRUD。 ADO无法对您执行此操作,因为您没有数据完整性。

一个可能的解决方案是将CRUD放在业务逻辑层..或类似的东西中。

假设您有一个OrderBll可以控制:

public class OrderBll
{
    private DB1Context _DB1Context = new DB1Context();
    private DB2Context _DB2Context = new DB2Context();

    public List<Orders> GetOrders()
    {
        var orders = _DB2Context.Orders.Where(???).ToList();
        var productIds = orders.Select(x => x.ProductId).Distinct().ToArray();
        var products = _DB1Context.Products.Where(x => productIds.Contains(x.Id)).ToList(); // Optimize the load of all products in orders

        // Set the product object in the order list
        foreach( var order in orders )
        {
             order.Product = products.FirstOrDefault(x=>x.Id == order.ProductId);
        }
        return orders;
    }
}

请记住,您必须像Product一样在Orders中映射Ignore属性。

因此,您必须自己设置外键并进行所有约束检查。

但是,如果其他人有更好的解决方案,我将很高兴知道。

答案 1 :(得分:0)

理想情况下,这就是您的目标。

  1. 将订单和产品放在同一数据库中。这样便可以在订单和产品之间建立关系。您最终将获得一个EF上下文,这将为您提供可靠的解决方案。

如果由于某种原因您无法在与产品相同的数据库中下订单,那么解决方案仍然有其自身的局限性。

  1. 您可以将product表从DB1复制到DB2,例如,复制每分钟运行一次。您可以编写自己的复制组件或使用数据库的复制功能。如果可以在DB2中删除产品,则复制可以删除DB1中的产品和订单,或者只是标记已删除的产品。由您决定。如果PRJ2可以更新产品表,则必须同时进行复制。这变得更加复杂。此解决方案的EF上下文将包含从订单到产品的关系,以及从产品到订单的关系。

  2. 另一个解决方案是在DB1中保留一个“代理”产品表,其中包含订单中引用的产品的ID。在业务逻辑中的任何地方,您都决定是否需要从DB1访问实际产品表。例如,当创建一个新订单时,您将访问DB1中的产品,如果没有,则将它们的ID插入代理表中。显示订单产品时,您首先要从DB1检索订单的产品ID,然后再从DB1检索其完整描述。在更新产品库存时,作为创建订单的一部分,您可能会使用跨DB的事务访问DB1!和DB2。