【问题标题】:Entity Framework - Disconnected Contexts and Duplicate Records实体框架 - 断开的上下文和重复的记录
【发布时间】:2017-06-09 15:47:55
【问题描述】:

我正在使用 Entity Framework 6。当我将导航属性更新为一个对象,然后执行 SaveChanges(),而不是引用现有的对象时,它会在引用表中创建一个副本。

下面有一些例子:

以下示例按预期工作。它创建了一个“客户”和一个“订单”并成功地将它们关联起来:

// Homer Simpson buys some Duff beer

Console.WriteLine("Homer Simpson is buying Duff beer");

Customer customer = new Customer
{
    Name = "Homer Simpson"
};

Order order1 = new Order
{
    Description = "Duff Beer"
};

customer.Orders.Add(order1);

using (EFContext db = new EFContext())
{
    db.Customers.Add(customer);
    DisplayChanges(db);
    db.SaveChanges();
}

输出

Homer Simpson is buying Duff beer
ConsoleApplication1.Objects.Customer - Added
ConsoleApplication1.Objects.Order - Added

但是,如果我尝试添加订单并关联现有客户,当我保存更改时,它会复制数据库中的客户对象以及我创建的现有订单:

// Homer Simpson buys some Duff beer

Console.WriteLine("Homer Simpson is buying Duff beer");

Customer customer = new Customer
{
    Name = "Homer Simpson"
};

Order order1 = new Order
{
    Description = "Duff Beer"
};

customer.Orders.Add(order1);

using (EFContext db = new EFContext())
{
    db.Customers.Add(customer);
    DisplayChanges(db);
    db.SaveChanges();
}

// Homer Simpson buys some Buzz Cola

Console.WriteLine("\r\nHomer Simpson is buying Buzz Cola");

Order order2 = new Order
{
    Description = "Buzz Cola",
    Customer = customer
};

using (EFContext db = new EFContext())
{
    db.Orders.Add(order2);
    DisplayChanges(db);
    db.SaveChanges();
}

输出

Homer Simpson is buying Duff beer
ConsoleApplication1.Objects.Customer - Added
ConsoleApplication1.Objects.Order - Added

Homer Simpson is buying Buzz Cola
ConsoleApplication1.Objects.Order - Added
ConsoleApplication1.Objects.Customer - Added
ConsoleApplication1.Objects.Order - Added

如果我设置外键而不是导航属性,则记录不会重复。但是,在这种情况下,我无法访问相关对象的属性,直到我明确加载它:

// Homer Simpson buys some Duff beer

Console.WriteLine("Homer Simpson is buying Duff beer");

Customer customer = new Customer
{
    Name = "Homer Simpson"
};

Order order1 = new Order
{
    Description = "Duff Beer"
};

customer.Orders.Add(order1);

using (EFContext db = new EFContext())
{
    db.Customers.Add(customer);
    DisplayChanges(db);
    db.SaveChanges();
}

// Homer Simpson buys some donuts

Console.WriteLine("\r\nHomer Simpson is buying donuts");

Order order3 = new Order
{
    Description = "Donuts",
    CustomerID = 1
};

if (order3.Customer == null)
{
    Console.WriteLine("Customer is null before save!");
}

else
{
    Console.WriteLine("The customer is " + customer.Name + " before save!");
}

using (EFContext db = new EFContext())
{
    db.Orders.Add(order3);
    DisplayChanges(db);
    db.SaveChanges();
}

if (order3.Customer == null)
{
    Console.WriteLine("Customer is null after save!");
}

else
{
    Console.WriteLine("The customer is " + customer.Name + " after save!");
}

using (EFContext db = new EFContext())
{
    db.Orders.Attach(order3);
    db.Entry(order3).Reference(x => x.Customer).Load();
}

if (order3.Customer == null)
{
    Console.WriteLine("Customer is null after forced load!");
}

else
{
    Console.WriteLine("The customer is " + customer.Name + " after forced load!");
}

输出

Homer Simpson is buying Duff beer
ConsoleApplication1.Objects.Customer - Added
ConsoleApplication1.Objects.Order - Added

Homer Simpson is buying donuts
Customer is null before save!
ConsoleApplication1.Objects.Order - Added
Customer is null after save!
The customer is Homer Simpson after forced load!

有人可以提供任何建议吗?我知道您可以手动附加和分离实体,但话虽如此,我正在处理一些非常复杂的对象。我想找到一种简单的方法来控制实体框架中的更改跟踪。

问候

彼得·迪根

【问题讨论】:

  • 没有简单的方法 - 在 EF 中使用断开连接的对象图从来都不是一件容易/简单的事情。您可以尝试尝试解决该主题的GraphDiff 包。不幸的是,作者不再支持它。

标签: entity-framework entity-framework-6


【解决方案1】:

当您将客户对象 附加 到订单 2 时,它正在插入一个新客户对象,我认为您应该始终使用外键而不是附加实体,并加载属性部分当然,您不会将客户对象附加到订单,因为您只是插入了它 如果您检查public virtual <T> Add(T entity),因为您可以看到它返回对象本身,而不包括任何其他对象,客户对象在您加载它之前不会被加载,我猜这是有道理的,在您的示例中,您使用显式加载来加载客户对象,如果您想避免这种情况,您可以启用延迟加载并始终获取客户对象而不显式加载它。简而言之,始终使用 fk,并且当您需要实体加载它(延迟加载或显式)时,附加对象绝不是好的做法,除非您想将所有对象插入在一起,或者您不关心重复项。 我希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    相关资源
    最近更新 更多