我正面临着一个问题,即让Entity Framework正确地从yield return中保存结果。为了说明问题,我创建了两组方法,一组返回实体,另一组使用yield return返回IEnumerable。期刊引用UserProfile。
设置1:
public static UserProfile CreateUser()
{
return new UserProfile() {
UserId = Guid.Parse("60a3987c-0aa6-4a93- a5d2-68c51122858b"),
UserName = "jason"
};
}
public static Journal CreateJournal(UserProfile userProfile)
{
return new Journal() { UserProfile = userProfile };
}
设置2:
public static IEnumerable<UserProfile> CreateUsers()
{
yield return new UserProfile() {
UserId =
Guid.Parse("02cd1e9f-5947-4b08-9616-5b4f4033d074"),
UserName = "john"
};
}
public static IEnumerable<Journal> CreateJournals(UserProfile userProfile)
{
yield return new Journal() { UserProfile = userProfile };
}
TestSet1和TestSet2分别保存Set1和Set2的结果。 TestSet1可以工作,但TestSet2会抛出违反PRIMARY KEY约束'PK_dbo.UserProfiles'的异常。另一个观察 - 如果我初始化List并返回它而不是yield return那么它就可以了。
public static void TestSet1()
{
var u = CreateUser();
var j = CreateJournal(u);
_db.UserProfiles.Add(u);
_db.Journals.Add(j);
_db.Commit();
}
public static void TestSet2()
{
var uList = CreateUsers();
var jList = CreateJournals(uList.ElementAt(0));
_db.UserProfiles.Add(uList.ElementAt(0));
_db.Journals.Add(jList.ElementAt(0));
_db.Commit();
}
您对Set2中的收益率返回无效的看法是什么? 感谢
答案 0 :(得分:1)
发生的事情是因为您实际上没有实现列表,所以您创建了2个UserProfile对象。如果你在这一行上设置一个断点,你可以看到这个:
yield return new UserProfile() { UserId = Guid.Parse("02cd1e9f-5947-4b08-9616-5b4f4033d074"), UserName = "john"};
你会注意到它被调用了两次 - 所以jList函数不是获取为uList创建的原始UserProfile,而是获得一个 new UserProfile对象。现在,虽然他们拥有相同的Guid,但他们在技术上并不相同,因为他们是引用类型而且他们没有指向同一个地方。然后ChangeTracker将看到它们不相等并尝试在数据库中创建2个对象,一个用于UserProfiles.Add(),然后第二个附加到您的jList,具有相同的Guid,这就是您如何得到错误
您可以通过在Test2函数中的CreateUsers上调用ToList()来修复代码,将列表实现到内存中,以便一切都匹配。
public static void TestSet2()
{
var uList = CreateUsers().ToList();
var jList = CreateJournals(uList.ElementAt(0));
_db.UserProfiles.Add(uList.ElementAt(0));
_db.Journals.Add(jList.ElementAt(0));
_db.Commit();
}