简体   繁体   English

实体框架代码前两个导航属性到/来自一个抽象实体

[英]Entity Framework Code First Two navigationProperty to/from one abstract entity

The following entities is my code first which PersonParameter is an abstract class and Shirt and Shoes are inherited from it with typ(1,2)以下实体首先是我的代码,其中 PersonParameter 是一个抽象类,而 Shirt 和 Shoes 是从它继承而来的 typ(1,2)

[Table("Person")]
public class Person
{
    [Key]
    public int id { get; set; }
    public string Name { get; set; }

    public int? shirtID { get; set; }
    public int? shoesID { get; set; }

    [ForeignKey("shirtID")]
    public Shirt Shirt { get; set; }
    [ForeignKey("shoesID")]
    public Shoes Shoes { get; set; }
}

[Table("PersonParameter")]
public abstract class PersonParameter
{
    public int id { get; set; }
    public string Title { get; set; }
    public string Value { get; set; }

    public List<Person> Persons { get; set; }
}

public class Shirt : PersonParameter
{

}
public class Shoes : PersonParameter
{

}

and for model dbcontext和模型 dbcontext

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonParameter>()
        .Map<Shirt>(p => p.Requires("typ").HasValue(1))
        .Map<Shoes>(p => p.Requires("typ").HasValue(2));
}

but the above codes will create unwanted field PersonParameter_id in Person table:但是上面的代码会在 Person 表中创建不需要的字段 PersonParameter_id :

public override void Up()
{
    CreateTable(
        "dbo.PersonParameter",
        c => new
            {
                id = c.Int(nullable: false, identity: true),
                Title = c.String(),
                Value = c.String(),
                typ = c.Int(nullable: false),
            })
        .PrimaryKey(t => t.id);

    CreateTable(
        "dbo.Person",
        c => new
            {
                id = c.Int(nullable: false, identity: true),
                Name = c.String(),
                shirtID = c.Int(),
                shoesID = c.Int(),
                PersonParameter_id = c.Int(),
            })
        .PrimaryKey(t => t.id)
        .ForeignKey("dbo.PersonParameter", t => t.shirtID)
        .ForeignKey("dbo.PersonParameter", t => t.shoesID)
        .ForeignKey("dbo.PersonParameter", t => t.PersonParameter_id)
        .Index(t => t.shirtID)
        .Index(t => t.shoesID)
        .Index(t => t.PersonParameter_id);

}

how can I solve it (PersonParameter_id) I did some FluentApi with HasOptional.WithMany but didn't solve.我该如何解决它(PersonParameter_id)我用 HasOptional.WithMany 做了一些 FluentApi 但没有解决。

EDIT编辑
After some test, found that for non abstract class it create extra id too and the one solution for fixing that issue is removing navigation property from parameter class and adding it to the inheritance classes (shirt and shoes)经过一些测试,发现对于非抽象类,它也会创建额外的 id,解决该问题的一种解决方案是从参数类中删除导航属性并将其添加到继承类(衬衫和鞋子)中

The reason you end up with one additional FK on Persons table is because of the Persons property on PersonParameter class.您最终在 Persons 表上多了一个 FK 的原因是因为 PersonParameter 类上的 Persons 属性。 Basically EF cannot relate that to any of the current two relationships defined (Shirt and Shoes) and figured that Persons property must have been a third relationship between Persons and PersonParamter tables and therefore creates a third FK (PersonParameter_id) to create this relationship.基本上 EF 无法将其与当前定义的两个关系(衬衫和鞋子)中的任何一个相关联,并认为 Persons 属性必须是 Persons 和 PersonParamter 表之间的第三种关系,因此创建了第三个 FK (PersonParameter_id) 来创建这种关系。 As a result, you end up with 3 uni-directional Many to One relationships from PersonParameter to Persons.因此,您最终会得到 3 个从 PersonParameter 到 Persons 的单向多对一关系。

To fix this, you need to explicitly tell EF that Persons is in fact the Inverse Property of Shoes and Shirts since there is no way that EF can pick that up automatically.要解决此问题,您需要明确告诉 EF Persons 实际上是鞋子和衬衫的逆属性,因为 EF 无法自动获取它。 You can do that with fluent API or by Annotations like this:您可以使用 fluent API 或通过这样的注释来做到这一点:

[Table("PersonParameter")]
public abstract class PersonParameter
{
    public int id { get; set; }
    public string Title { get; set; }
    public string Value { get; set; }
}

public class Shirt : PersonParameter
{
    [InverseProperty("Shirt")]
    public List<Person> Persons { get; set; }
}

public class Shoes : PersonParameter
{
    [InverseProperty("Shoes")]
    public List<Person> Persons { get; set; }
}


You can also achieve this by using the Fluent API:您还可以使用 Fluent API 来实现这一点:

modelBuilder.Entity<Shirt>()
    .HasMany(s => s.Persons)
    .WithOptional(p => p.Shirt)
    .HasForeignKey(p => p.shirtID);

modelBuilder.Entity<Shoes>()
    .HasMany(s => s.Persons)
    .WithOptional(p => p.Shoes)
    .HasForeignKey(p => p.shoesID);

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

相关问题 实体框架代码优先:两个DbContext和一个数据库初始化程序 - Entity Framework Code First : Two DbContext and one database initializers 实体框架代码优先 - 将两个字段联合成一个集合 - entity framework code first - Union of the two fields into one collection 条件两个属性之一必须为null Entity Framework Code First - Condition one of two properties to be different of null Entity Framework Code First 首先在实体框架代码中连接具有一对多关系的两个表 - Joining two tables with one to many relatipnship in entity framework code first Entity Framework Core - 代码优先 - 两个外键 - 一张表 - Entity Framework Core - Code First - Two Foreign Keys - One Table 实体框架代码优先从两个表和一对一的关系创建类 - Entity Framework Code First creates classes from two tables and relationships one to many 可从代码优先实体框架中查询两个表 - IQueryable two tables from Code First Entity Framework 实体框架代码优先 - 来自同一个表的两个外键 - Entity Framework Code First - two Foreign Keys from same table 实体框架设计器NavigationProperty自定义变量 - Entity Framework Designer NavigationProperty Custom Variable 实体框架,高效的 NavigationProperty.OfType 查询 - Entity Framework, efficient NavigationProperty.OfType query
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM