实体框架6 - 基类的继承和导航属性

时间:2014-06-30 11:02:19

标签: c# entity-framework inheritance orm entity-framework-6

导航属性和继承存在问题。

这是我的问题: 我有一个基础Person类,以及继承自User的类WorkerPerson。在数据库级别上,我使用单表继承或每层次表(TPH)继承。所以有一个带有鉴别器列的表。

UserWorker都需要Company关系,所以我想在Person类上定义它。

我像这样定义我的模型:

[Table("mydb.person")]
public abstract partial class Person
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long ID { get; set; }

    public long? CompanyID { get; set; }
    [ForeignKey("CompanyID")]
    public virtual Company Company { get; set; }
    ...
}

public partial class User : Person
{
    ...
}

public partial class Worker : Person
{
    ....
}

[Table("mydb.company")]
public partial class Company
{
    public Company()
    {
        this.People = new HashSet<Person>();
        this.Users = new HashSet<User>();
        this.Workers = new HashSet<Worker>();
    }

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long ID { get; set; }

    public virtual ICollection<Person> People { get; set; }

    public virtual ICollection<User> Users { get; set; }

    public virtual ICollection<Worker> Workers { get; set; }

    ...
}

现在,当我尝试进行查询以获取用户和相关公司时,例如:

dbSet.Where(u => u.Username == username).Include(x => x.Company).FirstOrDefault();

查询失败,出现此异常:

  

'字段列表

中的未知列'Extent1.Company_ID'

如果我检查结果SQL,它看起来像这样:

SELECT
1 AS `C1`, 
@gp2 AS `C2`, 
`Extent1`.`ID`, 
`Extent1`.`CompanyID`, 
`Extent1`.`Username`,
...
`Extent1`.`Company_ID`
FROM `person` AS `Extent1`
 WHERE `Extent1`.`Discriminator` = @gp1 

它包含额外的Company_ID列,该列不存在。

我尝试了一些事情,没有成功:

  • 将列从CompanyID重命名为Company_ID - &gt;它在SQL中生成Column_ID1并抛出相同的异常
  • Users移除WorkersCompany关系 - &gt;它抛出一个例外,说它不知道如何映射UserCompany个实体:
  

无法确定之间关联的主要结束   类型'Models.User'和'Models.Company'。这个的主要目的   必须使用以下任一方式显式配置关联   关系流畅的API或数据注释。

  • 如果我从Company删除所有3个导航属性,则会抛出与上面相同的映射异常

目前我已经没有“干净”的想法了。唯一可行的方法是做一些肮脏的黑客攻击,定义子类的所有关系,如果需要用户和工作者,则在基类中进行单独的查询和合并。

你有什么建议吗?

2 个答案:

答案 0 :(得分:5)

删除Users and Workers集合属性。

public virtual ICollection<User> Users { get; set; }

public virtual ICollection<Worker> Workers { get; set; }

由于您的公司导航属性是在Person上定义的,因此关联的后退导航属性必须是人员的ICollection。

People集合将包含所有关联的工作人员和用户。另外两个属性Users和Workers被解释为全新的关系,因为您没有相应的属性,而User或Worker EF上的外键实际上会生成它。

答案 1 :(得分:2)

回答评论。仅仅为了格式化作为第二个答案; - )

如果您从公司开始,请急切加载

var companies = db.Company.Include(p => p.People);

它将永远得到用户和工人。

如果您从人们那里开始使用急切加载。

var users = db.People.OfType<User>().Include(p => p.Company).ToList();
var companies = users.Select(p => p.Company).Distinct().ToList();

贵公司的人员导航属性只有用户。

此外,您可以执行两个单独的语句,数据库上下文的修复将自动填充导航属性。

var company = db.Company.Where(p => p.ID > 100).ToList();
var copanyUsers = db.Company.Where(p => p.ID > 100)
                      .SelectMany(p => p.People).OfType<User>().ToList();
相关问题