C# 实体框架外键跟踪导致问题

C# 实体框架外键跟踪导致问题,c#,.net,entity-framework,C#,.net,Entity Framework,与EF4合作,VS 2010中的模型优先方法: 考虑以下EntityModel: “OrderBase”是一个抽象实体,只有一个属性“Name” “Detail”(具有一个属性“Text”)是与“OrderBase”具有多对一关联的实体(即一个OrderBase具有多个细节) “Comment”(带有一个属性“Text”)是与“OrderBase”有多对一关联的实体(即一个OrderBase有多个注释) “MusicRecorder”是从“OrderBase”派生的实体,只有一个属性“Quant

与EF4合作,VS 2010中的模型优先方法:

考虑以下EntityModel:

“OrderBase”是一个抽象实体,只有一个属性“Name”

“Detail”(具有一个属性“Text”)是与“OrderBase”具有多对一关联的实体(即一个OrderBase具有多个细节)

“Comment”(带有一个属性“Text”)是与“OrderBase”有多对一关联的实体(即一个OrderBase有多个注释)

“MusicRecorder”是从“OrderBase”派生的实体,只有一个属性“Quantity”(int)

“SongOrder”是从“OrderBase”派生的实体,只有一个属性“Length”(int)。SongOrder与MusicRecorder有多对一的关系(即一个MusicRecorder有多个SonoOrder)

有关快速概述: 想发布datamdel的图像,但我不被允许。。。关于数据模型的任何问题

现在我生成数据库,执行ddl脚本并尝试运行以下代码:

using (DataContainer container = new DataContainer())
{
    MusicOrder musicOrder = new MusicOrder{Name = "Oldies", Quantity = 1};
    SongOrder songOrder = new SongOrder {Name = "Great balls of fire", Length = 240};
    songOrder.Details.Add(new Detail{Text = "Song from Jerry Lee Lewis"});
    songOrder.Comments.Add(new Comment{Text = "Cool song"});

    container.OrderBaseSet.AddObject(songOrder); //relevant line
    musicOrder.SongOrders.Add(songOrder);

    songOrder.Details.Clear();
    songOrder.Comments.Clear();
    container.OrderBaseSet.AddObject(musicOrder);
    container.SaveChanges();
}
using (DataContainer container = new DataContainer())
{
    MusicOrder musicOrder = new MusicOrder{Name = "Oldies", Quantity = 1};
    SongOrder songOrder = new SongOrder {Name = "Great balls of fire", Length = 240};
    songOrder.Details.Add(new Detail{Text = "Song from Jerry Lee Lewis"});
    songOrder.Comments.Add(new Comment{Text = "Cool song"});

    musicOrder.SongOrders.Add(songOrder);

    songOrder.Details.Clear();
    songOrder.Comments.Clear();

    container.OrderBaseSet.AddObject(songOrder); //relevant line
    container.OrderBaseSet.AddObject(musicOrder);
    container.SaveChanges();
}
在这种情况下,“SaveChanges”会导致一个异常,告诉我有关缺少外键关系的信息

但是如果我移动线

container.OrderBaseSet.AddObject(songOrder);
在“清除”部分之后,产生以下代码:

using (DataContainer container = new DataContainer())
{
    MusicOrder musicOrder = new MusicOrder{Name = "Oldies", Quantity = 1};
    SongOrder songOrder = new SongOrder {Name = "Great balls of fire", Length = 240};
    songOrder.Details.Add(new Detail{Text = "Song from Jerry Lee Lewis"});
    songOrder.Comments.Add(new Comment{Text = "Cool song"});

    container.OrderBaseSet.AddObject(songOrder); //relevant line
    musicOrder.SongOrders.Add(songOrder);

    songOrder.Details.Clear();
    songOrder.Comments.Clear();
    container.OrderBaseSet.AddObject(musicOrder);
    container.SaveChanges();
}
using (DataContainer container = new DataContainer())
{
    MusicOrder musicOrder = new MusicOrder{Name = "Oldies", Quantity = 1};
    SongOrder songOrder = new SongOrder {Name = "Great balls of fire", Length = 240};
    songOrder.Details.Add(new Detail{Text = "Song from Jerry Lee Lewis"});
    songOrder.Comments.Add(new Comment{Text = "Cool song"});

    musicOrder.SongOrders.Add(songOrder);

    songOrder.Details.Clear();
    songOrder.Comments.Clear();

    container.OrderBaseSet.AddObject(songOrder); //relevant line
    container.OrderBaseSet.AddObject(musicOrder);
    container.SaveChanges();
}
一切正常

正如你所看到的,我知道如何处理异常,我知道“双重添加”歌曲顺序是没有意义的。但我想知道这是一个bug还是一个特性。为什么在我的第一个示例中抛出异常。如果能给我一个全面的解释,我将不胜感激。在我看来,实体框架也应该能够处理第一个示例,而不会抛出异常。所以我会说这是一只虫子

请随意评论;)


Andi

您不必将songorder添加到base。只需将歌曲添加到音乐中,然后将音乐添加到基础


最可能的问题是你不喜欢添加与音乐无关的歌曲。

这是因为调用
AddObject
不仅会添加单个实体,还会添加所有未附加到上下文的相关实体。因此,当您在第一个示例中调用
AddObject(songOrder)
时,您还添加了
Detail
Comment
。但在此之后,您可以在导航属性上调用
Remove
,以同时删除
Detial
Comment
<附加实体上的code>Remove只会中断关系,但不会从上下文中删除
Detail
Comment
(只会将它们的主要关系设置为null)因此,一旦您尝试调用
SaveChanges
,它就会爆炸,因为您试图保存
Detail
Comment
,而不关联
OrderBase
(我猜关系是非空的)

在第二个示例中,
Comment
Detail
在向上下文添加顺序之前被删除,因此其行为符合预期


这不是一个bug,而是一个“特性”。

谢谢你的回答。我看不到这里的“功能”。如果实体框架足够“智能”,可以首先添加细节和注释,而我没有向数据库提交任何内容,那么它也应该足够智能,可以从上下文中删除所有这些对象。总而言之:实体上下文的行为总是好像所有内容都立即提交到数据库。所以我必须把它看作是数据库存储而不是对象上下文。嗨,谢谢你的回答。实体框架负责这些“多重”添加。即,再次添加已通过引用添加的对象不会导致数据库中出现异常或多个对象。