C# Конфигурация ядра Entity Framework InvalidOperationException: тип CLR 'ICollection <xxx>' не реализует 'IEnumerable <yyy>' - PullRequest
0 голосов
/ 21 апреля 2020

Я работаю над VS 2019, C# 8.0, Net 4.8, EFCore 3.1.3 для SQL Сервер в Code-First.

У меня есть общий c код для управлять связью NN между двумя сущностями:

public abstract partial class NNLink<IdentifierA, IdentifierB>
    where IdentifierA : Identifier
    where IdentifierB : Identifier
{
    [Required]
    public int Identifier1ID { get; set; }

    public IdentifierA Identifier1 { get; set; }

    [Required]
    public int Identifier2ID { get; set; }

    public IdentifierB Identifier2 { get; set; }
}

С

public abstract partial class Identifier
{
    [Key]
    public int ID { get; set; }
}

Я использую это так:

public class CommandProductLink : NNLink<Command, Product>
{
    public int Quantity { get; set; }
}

public class Command : Identifier
{
    public virtual ICollection<CommandProductLink> CommandProductLinks { get; set; } = new HashSet<CommandProductLink>();
}

public class Product: Identifier
{
    public virtual ICollection<CommandProductLink> CommandProductLinks { get; set; } = new HashSet<CommandProductLink>();
}

И я кодирую обобщенную c конфигурацию для этого:

public abstract class NNLinkConfiguration<IdentifierA, IdentifierB> : IEntityTypeConfiguration<NNLink<IdentifierA, IdentifierB>>
    where IdentifierA : Identifier
    where IdentifierB : Identifier
{
    public virtual void Configure(EntityTypeBuilder<NNLink<IdentifierA, IdentifierB>> builder)
    {
        builder.HasKey(o => new { o.Identifier1ID, o.Identifier2ID });

        AddNames(builder);
    }

    protected virtual void AddNames(EntityTypeBuilder builder)
    {
        var objectName = typeof(IdentifierA).Name + typeof(IdentifierB).Name + "Link";

        builder.ToTable(objectName + "s");

        var identifier = nameof(Identifier);
        var id = nameof(Identifier.ID);
        var links = builder.GetType()
                           .GenericTypeArguments[0]
                           .GetProperties()
                           .Where(o => o.Name == identifier + "1" || o.Name == identifier + "2" );

        if (links.Count() != 2)
            throw new Exception("Both entities for NNLink not found.");

        foreach (var item in links)
            builder.Property(item.Name + id)
                   .HasColumnName(item.PropertyType.Name + id);
    }

Когда я пытаюсь добавить миграцию с помощью EFCore Tools, все работает правильно ... Хотя оба объекта не совпадают ...

Теперь я должен закодируйте NNLink в той же сущности, например:

public class CommandCommandLink : NNLink<Command, Command>
{
}

public class Command : Identifier
{
    public virtual ICollection<CommandCommandLink> CommandCommandLink_Children { get; set; } = new HashSet<CommandCommandLink>();
    public virtual ICollection<CommandCommandLink> CommandCommandLink_Parents { get; set; } = new HashSet<CommandCommandLink>();
}

2 проблемы:

  1. ColumnName одинаковы,
  2. EFCore не может найти ведьму для ссылки = > Невозможно определить отношение, представленное свойством навигации 'Command.CommandCommandLink_Children' типа 'ICollection'. Либо настройте отношение вручную, либо игнорируйте это свойство с помощью атрибута «[NotMapped]» или с помощью «EntityTypeBuilder.Ignore» в «OnModelCreating»

Первая проблема, легко, я добавляю счетчик в foreach l oop:

        var i = 0;
        var isSameLink = links.First().PropertyType == links.Last().PropertyType;

        foreach (var item in links)
            builder.Property(item.Name + id)
                   .HasColumnName(item.PropertyType.Name + (isSameLink ? ++i ; string.empty) + id);

Вторая проблема сложнее, я пробовал этот код перед foreach l oop:

            if (isSameLink)
            {
                builder.HasOne(identifier + "1").WithMany().HasForeignKey(identifier + "1" + id);
                builder.HasOne(identifier + "2").WithMany().HasForeignKey(identifier + "2" + id);
            }

Та же ошибка ...

Я попытался с именем доступа:

                builder.HasOne(identifier + "1").WithMany("CommandCommandLink_Children").HasForeignKey(identifier + "1" + id);
                builder.HasOne(identifier + "2").WithMany("CommandCommandLink_Parents").HasForeignKey(identifier + "2" + id);

Теперь у меня есть эта ошибка: System.InvalidOperationException: Невозможно добавить свойство навигации коллекции 'CommandCommandLink_Children' к типу сущности 'Command', потому что его тип CLR «ICollection » не реализует «IEnumerable >». Свойства навигации по коллекции должны реализовывать IEnumerable <> связанной сущности.

Что я не понимаю, так это: CommandCommandLink наследует от NNLink и ICollection в IEnumerable, поэтому ICollection является IEnumarable >.

Где моя ошибка?

У меня есть решение для управления ею:

public class CommandCommandLinksConfiguration : IEntityTypeConfiguration<CommandCommanLink>
{
    public void Configure(EntityTypeBuilder<CommandCommanLink> builder)
    {
        builder.HasKey(o => new { o.Identifier1ID, o.Identifier2ID });

        builder.HasOne(o => o.Identifier1)
               .WithMany(o => o.CommandCommandLink_Children)
               .HasForeignKey(o => o.Identifier1ID);

        builder.HasOne(o => o.Identifier2)
               .WithMany(o => o.CommandCommandLink_Parent)
               .HasForeignKey(o => o.Identifier2ID);

        // It is the same:
        //builder.HasOne("Identifier1")
        //       .WithMany("CommandCommandLink_Children")
        //       .HasForeignKey("Identifier1ID");

        //builder.HasOne("Identifier2")
        //       .WithMany("CommandCommandLink_Parents")
        //       .HasForeignKey("Identifier2ID");
    }
}

В конфигурации generi c я могу найти все имена, но у меня всегда есть эта ошибка: свойство навигации коллекции «CommandCommandLink_Children» не может быть добавлено к типу сущности «Command», поскольку его тип CLR «ICollection » не реализует «IEnumerable >» , Свойства навигации по коллекции должны реализовывать IEnumerable <> связанной сущности.

Я хотел бы остаться в generi c, используя? Кто-нибудь может мне помочь?

Большое спасибо за внимание и чтение до конца ...

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