Можно ли иметь несколько свойств коллекции объектов с одинаковым базовым классом (TPH) внутри одного объекта? - PullRequest
0 голосов
/ 06 мая 2018

В своем проекте я использую Entity Framework core 2.0. Следующий код немного упрощен. Есть такие модели:

public class Site
{
    public int Id { get; set; } 
    public string Name { get; set; }
    public ICollection<AudioLink> AudioLinks { get; set; }
    public ICollection<VideoLink> VideoLinks { get; set; }
}

public abstract class Link
{
    public int Id { get; set; }         
    public string Href { get; set; }

    public int SiteId { get; set; }
    public Site Site { get; set; }
}

public class AudioLink : Link
{
}

public class VideoLink : Link
{
}

Я использую Fluent API для настройки отношений:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<Site> Sites { get; set; }
    public DbSet<AudioLink> AudioLinks { get; set; }
    public DbSet<VideoLink> VideoLinks { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<Link>()
            .HasDiscriminator<byte>("LinkType")
            .HasValue<AudioLink>(1)
            .HasValue<VideoLink>(2);

        builder.Entity<Site >().HasMany(s => s.VideoLinks)
            .WithOne(l => l.Site)
            .HasForeignKey(l => l.SiteId);

        builder.Entity<Site >().HasMany(s => s.AudioLinks)
            .WithOne(l => l.Site)
            .HasForeignKey(l => l.SiteId);
    }
}

Похоже, что миграция и база данных созданы правильно. Но когда я создаю новый объект Site:

var site = new Site(){Id = 1, Name = "SiteA"}
var audioLink = new AudioLink(){Id = 1, Href = "abc", Site = site};

context.Sites.Add(site);
context.SaveChanges();
context.AudioLinks.Add(audioLink);// exception occurs
context.SaveChanges();

следующее исключение выдается "Невозможно привести объект типа 'ApplicationCore.Entities.AudioLink' к типу 'ApplicationCore.Entities.VideoLink'."
Не могли бы вы сказать, что я делаю не так?

1 Ответ

0 голосов
/ 07 мая 2018

Наследование не изменяет правило, согласно которому одно навигационное свойство ссылки может быть отображено только в одно обратное свойство навигации коллекции.

На самом деле происходит следующее: вторая HasMany / WithOne переопределяет предыдущую (вероятно, ошибка должна вызывать исключение), поэтому Link.Site сопоставляется с Site.AudioLinks (не то, что Site является свойством базовой сущности Site, поэтому совместно используется AudioLink и VideoLink).

Таким образом, необходимо либо удалить свойства Site и SiteId из базового класса и поместить их в производные классы (которые будут вводить 2 отношения FK), либо лучше использовать свойство навигации для одной коллекции базового типа. :

public class Site
{
    public int Id { get; set; } 
    public string Name { get; set; }
    public ICollection<Link> Links { get; set; }
}

и отображение:

builder.Entity<Site>().HasMany(s => s.Links)
   .WithOne(l => l.Site)
   .HasForeignKey(l => l.SiteId);

Вы всегда можете использовать оператор OfType(), чтобы получить AudioLinks или VideoLinks из Links как в запросе LINQ to Entities, так и в LINQ to Objects после материализации Site.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...