27

我已经阅读了一些与此特定错误消息有关的问题/答案,但我不太了解适当的解决方案。

我读过很多次,您应该创建 EF4 上下文,使用它,然后处理它。在我的整个应用程序中,我使用不同的上下文对象在这里和那里加载实体,然后最终希望将实体关联在一起。

我创建了一个简单的控制台应用程序,很容易导致错误。非常简单的模型用图表表示,然后是代码。

如何让两个不同的实体共享相同的上下文?我真的必须创建一个新的上下文,再次加载这两个实体(即使我已经拥有它们),只是为了关联它们并保存?

如果我只是错过了一个已经存在的、适当的问题/答案,请指出我正确的地方。

简单的 EF4 模型图

internal class Program {

    private static void Main(string[] args) {
        DeleteAllEntities();
        CreateInitialEntities();
        Owner o = LoadOwner();
        Child c = LoadChild();
        AssociateAndSave(o, c);
    }

    private static void AssociateAndSave(Owner o, Child c) {
        using (var context = new ModelEntities()) {
            // Exception occurs on the following line.
            o.Children.Add(c);
            context.Attach(o);
            context.SaveChanges();
        }
    }

    private static Owner LoadOwner() {
        using (var context = new ModelEntities()) {
            return ((from o in context.Owners
                     select o).First());
        }
    }

    private static Child LoadChild() {
        using (var context = new ModelEntities()) {
            return ((from c in context.Children
                     select c).First());
        }
    }

    private static void CreateInitialEntities() {
        using (var context = new ModelEntities()) {
            Owner owner = new Owner();
            Child child = new Child();
            context.Owners.AddObject(owner);
            context.Children.AddObject(child);
            context.SaveChanges();
        }
    }

    private static void DeleteAllEntities() {
        using (var context = new ModelEntities()) {
            List<Child> children = (from c in context.Children
                                    select c).ToList();
            foreach (var c in children)
                context.Children.DeleteObject(c);
            List<Owner> owners = (from o in context.Owners
                                  select o).ToList();
            foreach (var o in owners)
                context.Owners.DeleteObject(o);
            context.SaveChanges();
        }
    }
}
4

2 回答 2

22

您应该在同一上下文中获得对子对象和所有者对象的引用。一种方法是获取 id,然后将它们作为参数传递给AssociateAndSave(int oId, int cId)方法。

然后,您检索对同一上下文中对象的引用并制作附件。

private static void Main(string[] args)
{
    DeleteAllEntities();
    CreateInitialEntities();
    int oId = LoadOwnerId();
    int cId = LoadChildId();
    AssociateAndSave(oId, cId);
}

private static int LoadOwnerId()
{
    using (var context = new ModelEntities())
    {
        return (from o in context.Owners
                select o).First().Id;
    }
}

private static int LoadChildId()
{
    using (var context = new ModelEntities())
    {
        return (from c in context.Children
                select c).First().Id;
    }
}

private static void AssociateAndSave(int oId, int cId)
{
    using (var context = new ModelEntities())
    {
        var owner = (from o in context.Owners
                        select o).FirstOrDefault(o => o.ID == oId);
        var child = (from o in context.Children
                        select o).FirstOrDefault(c => c.ID == cId);

        owner.Children.Add(child);
        context.Attach(owner);
        context.SaveChanges();
    }
}
于 2013-03-07T15:09:23.683 回答
4

您不能使用另一个上下文的实例从一个上下文中删除对象,因为每个上下文单独跟踪其对象。

一个想法是为您的每个方法提供您的上下文类型的参数,以便您的操作在相同的上下文中进行。

前任:

private static void CrudOperationExample(DBContext contextInstane)
{
    //perform crud operations.
}

我想做得更好,我建议你寻找依赖注入,因为它在 ORM 中非常有帮助。

于 2013-03-07T15:09:00.360 回答