通过Entity Framework保存收益率回报的变化

时间:2012-09-17 03:06:24

标签: c# entity-framework return yield savechanges

我正面临着一个问题,即让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中的收益率返回无效的看法是什么? 感谢

1 个答案:

答案 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();
}

有关yield关键字如何运作的更多信息来自hereherehere