2017-01-24 1 views
1

Ich habe ein seltsames Problem mit EF Core 1.1 konfrontiert. Ich versuche, eine Anwendung zu erstellen, wo einige Entitäten getaggt werden können, daher habe ich eine abstrakte generische Klasse für die Relationstabellenliste erstellt. Das Problem ist, dass es scheint, als ob EF keine generischen abstrakten Klassen unterstützt, die FK (Id-Eigenschaft) funktioniert.Entity Framework Core unterstützt keine generischen abstrakten Entitäten mit Meny2Meny-Beziehung?

Hier sind Modelle:

public abstract class TaggedEntityBase<T> : EntityBase 
{ 
    public ICollection<T> EntityTags { get; set; } 
    public List<Tag> Tags { get { return EntityTags?.Select(x => x.Tag).ToList(); } } 
} 

public class AddressTag 
{ 
    public long TagId { get; set; } 
    public Tag Tag { get; set; } 
    public long EntityId { get; set; } 
    public Address Entity { get; set; } 
} 

public class Address : TaggedEntityBase<AddressTag> 
{ 
    public string Street { get; set; } 
    public string City { get; set; } 
} 
public class Tag : EntityBase 
{ 
    public string Name { get; set; } 
    public virtual ICollection<AddressTag> AddressTags { get; set; } 
} 

Der Model Builder-Mappings:

public DbSet<Address> Addresses { get; set; } 
    public DbSet<AddressTag> AddressTag { get; set; } 
    public DbSet<Tag> Tags { get; set; } 

    protected override void OnModelCreating(ModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<AddressTag>() 
      .ToTable("AddressTag"); 

     modelBuilder.Entity<AddressTag>() 
      .HasKey(t => new { t.EntityId, t.TagId }); 
     modelBuilder.Entity<AddressTag>() 
     .HasOne(pt => pt.Entity) 
      .WithMany(p => p.EntityTags) 
      .HasForeignKey(p => p.EntityId); 
     modelBuilder.Entity<AddressTag>() 
     .HasOne(pt => pt.Tag) 
      .WithMany(p => p.AddressTags) 
      .HasForeignKey(p => p.TagId); 

    } 

Es ist ein Fehler, wenn EF versuchen Schlagwörter

Eine nicht behandelte Ausnahme des Typs ‚System zu holen .Data.SqlClient.SqlException trat in Microsoft.EntityFrameworkCore.dll auf Weitere Informationen: Ungültiger Spaltenname "AddressId".

Ich habe nicht einmal diese Id-Konvention.

Hinweis: Wenn ich explizit public ICollection<AddressTag> EntityTags { get; set; } innerhalb Adresse POCO platzieren, dann funktioniert es perfekt, einschließlich EntityTags.Tag auch. Danke für jede Hilfe :)

+0

Hatte similiar Ausgabe – miechooy

+0

Die Probe unvollständig ist. "EntityBase" -Klasse fehlt und "öffentliche Liste Tags {get {return EntityTags?. Select (x => x.Tag). ToList(); }} 'kompiliert nicht (fehlende Einschränkung für' T'). Könnten Sie den Post mit den fehlenden Teilen aktualisieren, um ihn reproduzierbar zu machen? –

Antwort

1

Das Problem hat nichts mit generischen und/oder abstrakten Basis-Entity-Klassen zu tun.

Zuerst Ihre Beispielmodell der Kompilierung zu machen, ich habe die folgenden Klassen hinzugefügt

public abstract class EntityBase 
{ 
    public long Id { get; set; } 
} 

public abstract class EntityTagBase 
{ 
    public long TagId { get; set; } 
    public Tag Tag { get; set; } 
} 

modifiziert, um die AddressTag Klasse wie folgt:

public class AddressTag : EntityTagBase 
{ 
    public long EntityId { get; set; } 
    public Address Entity { get; set; } 
} 

und hinzugefügt where T : EntityTagBase Einschränkung TaggedEntityBase<T> Klasse zu ermöglichen, Tag Eigenschaft Accessor innerhalb Select(x => x.Tag).

So weit so gut. Der Tag bezogenen Teil der erzeugten Migration sieht wie folgt aus:

migrationBuilder.CreateTable(
    name: "Tags", 
    columns: table => new 
    { 
     Id = table.Column<long>(nullable: false) 
      .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn), 
     AddressId = table.Column<long>(nullable: true), 
     Name = table.Column<string>(nullable: true) 
    }, 
    constraints: table => 
    { 
     table.PrimaryKey("PK_Tags", x => x.Id); 
     table.ForeignKey(
      name: "FK_Tags_Addresses_AddressId", 
      column: x => x.AddressId, 
      principalTable: "Addresses", 
      principalColumn: "Id", 
      onDelete: ReferentialAction.Restrict); 
    }); 

Siehe AddressId Spalte und FK zu Addresses Tisch? Warum das? Aufgrund Ihrer Tags Eigenschaft:

public List<Tag> Tags { get { return ...; } } 

Es ist wahrscheinlich ein aktueller EF-Core Bug des Abbildens las eine einzige Sammlung Eigenschaft, aber der Nettoeffekt ist, dass es eine zu viel Beziehung zwischen Address und Tag was natürlich hält, ist nicht Ihr Absicht.

Im Allgemeinen würde ich empfehlen, das Entity-Modell sauber zu halten und solche "Helfer" -Eigenschaften - sowohl Collection- als auch Referenztyp - nicht einzubeziehen. Sie sehen aus wie Navigationseigenschaften, aber sie sind nicht, und es ist einfach, sie versehentlich in einer Abfrage zu verwenden, was den Ausführungsplan völlig ändert und zu unerwarteten Ausnahmen oder falschen Ergebnissen führt (falls die zugrunde liegende Eigenschaft nicht geladen ist). Nicht über die Verletzung einer allgemeinen Regel sprechen, um keine Eigenschaft zu erzeugen, die List zurückgibt, die kein Mitglied der Klasse ist, aber in jedem Eigenschaftszugriffsaufruf erstellt wird.

Kurz, einfach entfernen Sie diese Eigenschaft und das Problem wird weg sein. Oder wenn Sie es bestehen zu halten, dann schmücken sie mit NotMapped Daten Anmerkung:

[NotMapped] 
public List<Tag> Tags { get { return ...; } } 
+0

Sie sind völlig richtig. Ich habe es aus Versehen vor Deinem Beitrag herausgefunden aber trotzdem verstehe ich jetzt warum es AddressId war, und ich kann das Mapping einfach ignorieren. Vielen Dank –

Verwandte Themen