这是正常的实体框架行为吗?

时间:2012-10-03 10:05:18

标签: oop entity-framework-4.1 one-to-many

我在以下类之间有两对一关系

public class SiteMember
{
        public int SiteMemberID { get; set; }
        public virtual List<FriendshipInvitation> InvitationsSent { get; set; }
        public virtual List<FriendshipInvitation> InvitationsReceived { get; set; }
}

public class FriendshipInvitation
{
        public int InvitingUserID { get; set; }
        public SiteMember InvitingUser { get; set; }

        public int InvitedUserID { get; set; }
        public SiteMember InvitedUser{ get; set; }
}

然后在控制器中我有以下代码(从db加载一个SiteMember):

SiteMember sm = repoSiteMember.GetUserByName(User.Identity.Name);

此时

sm.InvitationsReceived.InvitingUserId = 1;
sm.InvitationsReceived.InvitingUser = null

然后我有以下行(从db加载所有SiteMembers):

IEnumerable<SiteMember> all = repoSiteMember.GetAll();

之后

sm.InvitationsReceived.InvitingUserId = 1 
sm.InvitationsReceived.InvitingUser = proxy to SiteMember object.

我的问题是:这是正常行为吗?我很确定我可以用include语句“修复”空指针,但我发现从db加载所有元素实际上改变了对象的状态是很奇怪的。 (null =&gt; proxy)。代理人应该从一开始就在那里吗?

修改 只是为了确认,include语句确实解决了空引用的问题,但这不是问题。

DataContext.Members
   .Include("InvitationsSent.InvitedUser")
   .Include("InvitationsReceived.InvitingUser")
   .FirstOrDefault(e => e.UserName == userName);

Edit2:现在包含的方法。

public SiteMember GetUserByName(string userName)
{
    return base.DataContext.Members.FirstOrDefault(e => e.UserName == userName);
}

public IEnumerable<SiteMember> GetAll()
{
    return base.DataContext.Members.ToList();
}

编辑3:您可能需要重新创建模型。

    modelBuilder.Entity<FriendshipInvitation>()
        .HasRequired(e => e.InvitedUser)
        .WithMany(e => e.InvitationsReceived)
        .HasForeignKey(e => e.InvitedUserID)
        .WillCascadeOnDelete(false);

    modelBuilder.Entity<FriendshipInvitation>()
        .HasRequired(e => e.InvitingUser)
        .WithMany(e => e.InvitationsSent)
        .HasForeignKey(e => e.InvitingUserID);


    modelBuilder.Entity<FriendshipInvitation>()
        .HasKey(e => new { e.InvitingUserID, e.InvitedUserID, e.InvitationNo });

1 个答案:

答案 0 :(得分:1)

是的,不同的行为是正常的,并且是因为 Relationship Fixup 而发生的。

当您只加载SiteMember FirstOrDefault InvitationsSent时,两个集合InvitationsReceivedvirtual将会在您访问它们时立即加载(或检查它们)调试器)因为它们被标记为FriendshipInvitation并且将应用延迟加载。但是这些集合中的InvitingUser不会延迟加载InvitedUservirtual,因为这些导航属性标记为SiteMember

说,您使用FirstOrDefault加载的SiteMember 1收到了来自InvitationsReceived 2的邀请,但未发送任何邀请。因此,InvitationsSent将包含一个元素,FriendshipInvitation将为空。该元素 - InvitingUser实体 - 将InvitedUser设为2,将InvitingUser设为1. null在这种情况下将为virtual,因为它不能被延迟加载(因为它不是SiteMember)并且InvitedUser 2尚未加载到上下文中。 (SiteMember但是SiteMember 1的动态代理,因为您已经加载了SiteMember 1,请参阅下一段。)

但是,如果您使用ToList()加载所有 SiteMemberToList() 2将被加载到InvitingUser 2执行查询的上下文中。 1}}。 EF会自动将InvitingUser 2设置为已加载的实体,称为 Relationship Fixup 。延迟加载virtual导航属性,因为非InvitingUser属性不支持延迟加载。

要获得一致的行为并且不依赖于关系修正,我建议您将InvitedUservirtual导航属性标记为{{1}}。