实体框架 - 断开的上下文和重复记录

时间:2017-06-09 15:47:56

标签: entity-framework entity-framework-6

我正在使用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

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

// 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!

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

此致

Peter Deegan

1 个答案:

答案 0 :(得分:0)

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