简体   繁体   English

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

[英]Entity Framework 6 - inheritance and navigation properties on base class

I have a problem with navigation properties and inheritance. 我对导航属性和继承有疑问。

This is my problem: I have a base Person class and classes User and Worker which inherit from Person . 这是我的问题:我有一个基本的Person类以及从Person继承的UserWorker类。 On the DB level I'm using single table inheritance or table per hierarchy (TPH) inheritance. 在数据库级别,我正在使用单表继承或按层次结构表(TPH)继承。 So there a single table with a discriminator column. 因此,有一个带有鉴别符列的表。

Both User and Worker need to have a Company relation, so I would like to define it on the Person class. UserWorker需要有一个Company关系,所以我想在Person类上定义它。

I define my model like this: 我这样定义我的模型:

[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; }

    ...
}

Now, when I try to do a query to get the user and related company, for example: 现在,当我尝试执行查询以获取用户和相关公司时,例如:

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

The query fails with this exception: 查询因以下异常而失败:

Unknown column 'Extent1.Company_ID' in 'field list “字段”列表中的未知列“ Extent1.Company_ID”

If I examine the result SQL it looks something like this: 如果我检查结果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 

It includes the extra Company_ID column, which doesn't exist. 它包括额外的Company_ID列,该列不存在。

I tried a few thing, nothing worked out: 我尝试了几件事,但没有解决:

  • renaming the column from CompanyID to Company_ID -> it generates a Column_ID1 in SQL and throws the same exception 将列从CompanyID重命名为Company_ID >它在SQL中生成Column_ID1并引发相同的异常
  • removing the Users and Workers relations from Company -> it throws an exception saying it doesn't know how to map User and Company entities: Company删除Users and Workers关系->抛出一个异常,它不知道如何映射UserCompany实体:

Unable to determine the principal end of an association between the types 'Models.User' and 'Models.Company'. 无法确定类型“ Models.User”和“ Models.Company”之间的关联的主要终点。 The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations. 必须使用关系流利的API或数据注释显式配置此关联的主要端。

  • If I remove all 3 navigation properties from Company it throws the same mapping exception as above 如果我从Company删除所有3个导航属性,则会引发与上述相同的映射异常

I'm out of "clean" ideas at the moment. 我目前没有“干净”的想法。 The only thing that could work is to do some dirty hack, define all the relations on child classes, and do separate queries and merging in the base class if both users and workers are required. 唯一可行的方法是进行一些肮脏的修改,定义子类上的所有关系,并在需要用户和工作人员的情况下分别进行查询和合并到基类中。

Do you have any suggestions? 你有什么建议吗?

Remove the Users and Workers collection properties. 删除“用户和工作人员”集合属性。

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

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

As your Company navigation property is defined on Person the associated back navigation property has to be an ICollection of Person. 由于您的公司导航属性是在Person上定义的,因此相关的后向导航属性必须是Person的ICollection。

The People collection will contain all the associated workers and users. 人员集合将包含所有关联的工作人员和用户。 The two extra properties Users and Workers are interpreted as completely new relationships and because you do not have corresponding properties and foreign keys on User or Worker EF generates it virtually. 用户和辅助程序这两个额外的属性被解释为全新的关系,因为您没有相应的属性,而用户或辅助程序EF上的外键实际上会生成它。

Answer to the comment. 回答评论。 Just for the sake of formatting as a second answer ;-) 只是为了格式化为第二个答案;-)

With eager loading if you start with the Company 如果您从公司开始,就渴望加载

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

It will always get the Users and the Workers. 它将始终获得用户和工人。

If you use eager loading starting at the people. 如果您使用急切的加载方式,则始于人们。

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

the People navigation property of your companies has just the Users. 您公司的“人员”导航属性只有“用户”。

Also you could execute two separate statements and the fixup of the database context will automatically fill the Navigation properties. 您也可以执行两个单独的语句,数据库上下文的修复程序将自动填充Navigation属性。

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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM