Я работаю над 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 проблемы:
- ColumnName одинаковы,
- 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, используя? Кто-нибудь может мне помочь?
Большое спасибо за внимание и чтение до конца ...