Entity Framework Code Первые два свойства навигации в/из одного абстрактного объекта

Следующие объекты - это мой код, который PersonParameter является абстрактным классом, а рубашка и обувь унаследованы от него с типом (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
{

}

и для модели 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));
}

но приведенные выше коды создадут нежелательное поле PersonParameter_id в таблице Person:

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

}

как я могу это решить (PersonParameter_id) Я сделал несколько FluentApi с HasOptional.WithMany, но не решил.

EDIT
После некоторого теста было обнаружено, что для неабстрактного класса он также создает дополнительный идентификатор, и единственным решением для устранения этой проблемы является удаление свойства навигации из класса параметров и добавление его в классы наследования (рубашка и обувь)


person Hamid    schedule 08.05.2016    source источник


Ответы (1)


Причина, по которой вы получаете один дополнительный FK в таблице Persons, связана со свойством Persons в классе PersonParameter. По сути, EF не может связать это ни с одним из двух определенных текущих отношений (Рубашка и Обувь) и решил, что свойство Persons должно быть третьим отношением между таблицами Persons и PersonParamter, и поэтому создает третий FK (PersonParameter_id) для создания этого отношения. В результате вы получите 3 однонаправленных отношения «многие к одному» от PersonParameter к Persons.

Чтобы исправить это, вам нужно явно указать EF, что Persons на самом деле является обратным свойством обуви и рубашки, поскольку EF никак не может подобрать это автоматически. Вы можете сделать это с помощью свободного 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; }
}


Этого также можно добиться с помощью 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);
person Morteza Manavi    schedule 08.05.2016
comment
но есть два FK в Person для PersonParameter (ShirtID и ShoesID), так зачем ему дополнительный FK? - person Hamid; 09.05.2016
comment
Спасибо за комментарий. Я обновил свой ответ соответственно. - person Morteza Manavi; 09.05.2016
comment
Спасибо. Я делал это раньше, но важно, чтобы это свойство навигации было внутри основного класса (PersonParameter), а не внутри его класса наследования, потому что это должен быть базовый класс. Также у меня есть тест для объявления общедоступных List‹Person› Persons { get; установлен; } как абстрактное свойство, и я считаю, что есть решение с Fluent API, которое сообщает ef об этих обратных свойствах. - person Hamid; 09.05.2016
comment
Я обновил свой ответ с помощью свободного API, но я не думаю, что EF позволяет вам иметь свойство Persons в базовом классе и, к сожалению, определять 2 разных отношения для каждого подкласса. - person Morteza Manavi; 09.05.2016