2012-03-12 99 views
1

请看看下面的代码:EF代码第一 - 继承和关系

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

我的问题是 - 有没有办法来设置FluentApi做出正确上述工作所示的关系?目前,当新的SomeEntityA对象被添加到用户时,EF会在SomeEntities表中创建一个具有正确设置的User_Id FK的新记录,但是在SomeEntitesA中,这是一个继承表,还有一个FK属性User_Id - 设置为null,当我尝试获取SomeEntites来自User对象的集合 - 它是空的。我明白为什么会发生这种情况,但我不确定是否有办法解决这个问题? ,在这一刻我想到的唯一解决办法是更换下面的代码:

public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 

有:

public virtual ICollection<SomeEntity> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntity> SomeEntitiesB { get; set; } 

和配置FluentApi。

任何想法将不胜感激。

回答

1

看一看这个问题/答案,这些类具有完全相同的结构,你的,有事情为什么不按预期工作的一个详细的解释:

Is inheritance of navigation properties supported?

由于Slauma指出,还有一种比较简单的解决方案来解决这个问题通过执行以下操作(从链接的答案被复制,并且要适合你的例子):

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    // this is necessary to have access to the related SomeEntityAs/SomeEntityBs 
    // also it cant be private otherwise EF will not overload it properly 
    public virtual ICollection<SomeEntity> SomeEntities { get; set; } 

    public IEnumerable<SomeEntityA> SomeEntitiesA { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
    public IEnumerable<SomeEntityB> SomeEntitiesB { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
} 
+0

顺便说一句:你可以从你的其他答案带来的解决方案(最后一个代码片段)这里的问题。因为这是一个真正的选择。它总是会加载所有的基本实体,然后'OfType'会在内存中过滤掉,所以会有潜在的数据加载开销。但另一方面,在基类中有'User',而不是像我的解决方案那样在派生类中“重复”。通过一切手段一个有趣的解决方案,值得考虑! (我会upvote :)) – Slauma 2012-03-12 23:24:03

+0

thx的提示,只是更新了答案。 – ntziolis 2012-03-13 00:03:22

+0

谢谢我认为我会坚持这种方法,但我想更多地了解它的性能?即使我将IEnumerable 更改为IQueryable类型,并且例如使用Take()方法,它是否仍会首先将所有这些实体加载到内存中? – 2012-03-13 15:06:16

1

您建议的解决方案也不起作用,因为您无法将两个导航属性User.SomeEntitiesAUser.SomeEntitiesB关联到同一端点SomeEntity.User。实际上,你将需要两个用户:

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserAId { get; set; } 
    [InverseProperty("SomeEntitiesA")] 
    public virtual User UserA { get; set; } 

    public int UserBId { get; set; } 
    [InverseProperty("SomeEntitiesB")] 
    public virtual User UserB { get; set; } 
} 

但你也可以保持集合类型,因为他们和移动用户派生实体:

public class SomeEntity 
{ 
    public int Id { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

你并不需要指定[InverseProperty]在这种情况下,因为约定现在将检测到正确的导航属性对。

+0

感谢您的回答,但主要的想法是让用户在基地上课,所以当我创建一个视图来显示这些实体,我可以显示用户名,无论类是A还是B类。 – 2012-03-13 15:04:24