EF-Code Zuerst "Ungültiger Spaltenname 'Diskriminator'", aber keine Vererbung

154

Ich habe eine Tabelle in meiner Datenbank mit dem Namen SEntries (siehe unten die Anweisung CREATE TABLE). Es hat einen Primärschlüssel, ein paar Fremdschlüssel und nichts Besonderes. Ich habe viele Tabellen in meiner Datenbank, die dieser ähnlich sind, aber aus irgendeinem Grund endete diese Tabelle mit einer Spalte "Diskriminator" in der EF-Proxy-Klasse.

So wird die Klasse in C # deklariert:

public class SEntry
{
    public long SEntryId { get; set; }

    public long OriginatorId { get; set; }
    public DateTime DatePosted { get; set; }
    public string Message { get; set; }
    public byte DataEntrySource { get; set; }
    public string SourceLink { get; set; }
    public int SourceAppId { get; set; }
    public int? LocationId { get; set; }
    public long? ActivityId { get; set; }
    public short OriginatorObjectTypeId { get; set; }
}

public class EMData : DbContext
{
    public DbSet<SEntry> SEntries { get; set; }
            ...
    }

Wenn ich versuche, dieser Tabelle eine neue Zeile hinzuzufügen, wird folgende Fehlermeldung angezeigt:

System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.

Dieses Problem tritt nur auf, wenn Sie Ihre C # -Klasse von einer anderen Klasse erben, SEntry jedoch nichts erbt (wie Sie oben sehen können).

Sobald ich den Tooltip zum Debugger erhalte, wenn ich mit der Maus über die EMData-Instanz für die SEntries-Eigenschaft fahre, wird außerdem Folgendes angezeigt:

base {System.Data.Entity.Infrastructure.DbQuery<EM.SEntry>} = {SELECT 
[Extent1].[Discriminator] AS [Discriminator], 
[Extent1].[SEntryId] AS [SEntryId], 
[Extent1].[OriginatorId] AS [OriginatorId], 
[Extent1].[DatePosted] AS [DatePosted], 
[Extent1].[Message] AS [Message], 
[Extent1].[DataEntrySource] AS [DataE...

Irgendwelche Vorschläge oder Ideen, wo Sie dieser Ausgabe auf den Grund gehen können? Ich habe versucht, die Tabelle, den Primärschlüssel und einige andere Dinge umzubenennen, aber nichts funktioniert.

SQL-Tabelle:

CREATE TABLE [dbo].[SEntries](
[SEntryId] [bigint] IDENTITY(1125899906842624,1) NOT NULL,
[OriginatorId] [bigint] NOT NULL,
[DatePosted] [datetime] NOT NULL,
[Message] [nvarchar](500) NOT NULL,
[DataEntrySource] [tinyint] NOT NULL,
[SourceLink] [nvarchar](100) NULL,
[SourceAppId] [int] NOT NULL,
[LocationId] [int] NULL,
[ActivityId] [bigint] NULL,
[OriginatorObjectTypeId] [smallint] NOT NULL,
CONSTRAINT [PK_SEntries] PRIMARY KEY CLUSTERED 
(
[SEntryId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,       ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[SEntries]  WITH CHECK ADD  CONSTRAINT [FK_SEntries_ObjectTypes] FOREIGN KEY([OriginatorObjectTypeId])
REFERENCES [dbo].[ObjectTypes] ([ObjectTypeId])
GO

ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_ObjectTypes]
GO

ALTER TABLE [dbo].[SEntries]  WITH CHECK ADD  CONSTRAINT [FK_SEntries_SourceApps] FOREIGN KEY([SourceAppId])
REFERENCES [dbo].[SourceApps] ([SourceAppId])
GO

ALTER TABLE [dbo].[SEntries] CHECK CONSTRAINT [FK_SEntries_SourceApps]
GO
Marcelo Calbucci
quelle
16
Für die nächste Person, die einige Zeit damit verbringen wird, dies herauszufinden, ist es passiert, dass ich an einer anderen Stelle im Code eine Klasse hatte, die von SEntry geerbt wurde, obwohl es keine Klasse ist, die jemals in der Datenbank gespeichert werden würde . Alles was ich tun musste war [NotMapped] als Attribut dieser Klasse hinzuzufügen!
Marcelo Calbucci
Ich erhalte diesen Fehler, wenn ich nicht [NotMapped] auf ApplicationUser-Klasse in Identitymodel.cs
Heemanshu Bhalla

Antworten:

319

Es stellt sich heraus, dass Entity Framework davon ausgeht, dass für jede Klasse, die von einer POCO-Klasse erbt, die einer Tabelle in der Datenbank zugeordnet ist, eine Diskriminatorspalte erforderlich ist, auch wenn die abgeleitete Klasse nicht in der Datenbank gespeichert wird.

Die Lösung ist recht einfach und Sie müssen nur [NotMapped]ein Attribut der abgeleiteten Klasse hinzufügen .

Beispiel:

class Person
{
    public string Name { get; set; }
}

[NotMapped]
class PersonViewModel : Person
{
    public bool UpdateProfile { get; set; }
}

Selbst wenn Sie die Person-Klasse der Person-Tabelle in der Datenbank zuordnen, wird jetzt keine Spalte "Diskriminator" erstellt, da die abgeleitete Klasse dies hat [NotMapped].

Als zusätzlichen Tipp können Sie [NotMapped]Eigenschaften verwenden, die Sie keinem Feld in der Datenbank zuordnen möchten.

Marcelo Calbucci
quelle
7
ok, es gibt also 3 Stunden meines Lebens; (aber trotzdem. Ich sollte auch hinzufügen, um klar zu sein ... die abgeleiteten Klassen können ganz in der Ecke sein und werden in keiner Weise für Persistenz und EF verwendet
Ich
12
Wenn Sie [NotMapped] nicht finden, fügen Sie dem Projekt aus "Assembly Framework" einen Verweis auf: "System.ComponentModel.DataAnnotations" hinzu.
XandrUu
9
using System.ComponentModel.DataAnnotations.Schema;
Ygaradon
6
In meinem Fall habe ich jedoch eine Klasse geerbt, um mithilfe der untergeordneten Klasse eine Spalte in der DB-Tabelle hinzuzufügen. Daher kann ich dieses nicht zugeordnete Attribut nicht verwenden, um es zum Laufen zu bringen. Was sollte in diesem Fall meine Lösung sein?
Sohaib javed
4
In meinem Fall hat das Hinzufügen von nicht zugeordneten nicht geholfen. Ich habe nicht in allen Ansichtsmodellen zugeordnet
Heemanshu Bhalla
44

Hier ist die Fluent API-Syntax.

http://blogs.msdn.com/b/adonet/archive/2010/12/06/ef-feature-ctp5-fluent-api-samples.aspx

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName { 
        get {
            return this.FirstName + " " + this.LastName;
        }
    }
}

class PersonViewModel : Person
{
    public bool UpdateProfile { get; set; }
}


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // ignore a type that is not mapped to a database table
    modelBuilder.Ignore<PersonViewModel>();

    // ignore a property that is not mapped to a database column
    modelBuilder.Entity<Person>()
        .Ignore(p => p.FullName);

}
Walter Stabosz
quelle
Wäre es nicht besser, nur das [NotMapped]Attribut hinzuzufügen ?
Keith
1
@ Keith meine Antwort ist, wie man eine Spalte mit der Fluent API ignoriert, die keine Attribute wie [NotMapped] verwendet
Walter Stabosz
1
Keith, dies ist meiner Meinung nach die bevorzugte Antwort, da wir uns jetzt einem Code-First-Standard zuwenden und Walters Antwort für dieses Szenario besser geeignet ist, insbesondere wenn Sie am Ende Datenbankmigrationen verwenden.
Tahir Khalid
Wenn Sie das gegenteilige Problem haben (dh eine EF-gebundene Klasse, die von einer POCO-Klasse erbt), war dies die einzige Möglichkeit, dies zum Laufen zu bringen, ohne das Datenmodell mit EF zu verschmutzen.
Paul Michaels
8

Ich bin gerade darauf gestoßen, und mein Problem wurde dadurch verursacht, dass zwei Entitäten beide System.ComponentModel.DataAnnotations.Schema.TableAttributeauf dieselbe Tabelle verweisen.

beispielsweise:

[Table("foo")]
public class foo
{
    // some stuff here
}

[Table("foo")]
public class fooExtended
{
    // more stuff here
}

Wenn ich den zweiten von fooauf foo_extendedändere, wird dies für mich behoben und ich verwende jetzt Table Per Type (TPT).

Seph
quelle
Dies hat bei mir nicht funktioniert:The entity types 'AtencionMedica' and 'AtencionMedicaAP' cannot share table 'AtencionMedicas' because they are not in the same type hierarchy
James Reategui
Danke, hat mir geholfen, hatte das gleiche Problem mit der fließenden API: var entity = modelBuilder.Entity<EntityObject>().ToTable("ENTITY_TABLE")und dann eine andere Zeile mit der gleichen EntityObjectoder der gleichen ENTITY_TABLE.
Mathijs Flietstra
4

Ein anderes Szenario, in dem dies auftritt, ist, wenn Sie eine Basisklasse und eine oder mehrere Unterklassen haben, wobei mindestens eine der Unterklassen zusätzliche Eigenschaften einführt:

class Folder {
  [key]
  public string Id { get; set; }

  public string Name { get; set; }
}

// Adds no props, but comes from a different view in the db to Folder:
class SomeKindOfFolder: Folder {
}

// Adds some props, but comes from a different view in the db to Folder:
class AnotherKindOfFolder: Folder {
  public string FolderAttributes { get; set; }
}

Wenn diese DbContextwie Folderfolgt zugeordnet sind, tritt der Fehler "'Ungültiger Spaltenname' Diskriminator '" auf, wenn auf einen Typ zugegriffen wird, der auf dem Basistyp basiert:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
  modelBuilder.Entity<Folder>().ToTable("All_Folders");
  modelBuilder.Entity<SomeKindOfFolder>().ToTable("Some_Kind_Of_Folders");
  modelBuilder.Entity<AnotherKindOfFolder>().ToTable("Another_Kind_Of_Folders");
}

Ich fand, dass wir, um das Problem zu beheben, die Requisiten Foldereiner Basisklasse (die nicht zugeordnet ist OnModelCreating()) wie folgt extrahieren - OnModelCreatingsollte unverändert bleiben:

class FolderBase {
  [key]
  public string Id { get; set; }

  public string Name { get; set; }
}

class Folder: FolderBase {
}

class SomeKindOfFolder: FolderBase {
}

class AnotherKindOfFolder: FolderBase {
  public string FolderAttributes { get; set; }
}

Dies beseitigt das Problem, aber ich weiß nicht warum!

Fleischaxt
quelle
Danke, Meataxe - das hat mich ein oder zwei Stunden gekostet, aber das Schlimmste war, ich musste dieses Problem schon einmal gehabt haben, weil ich alle Basisklassen eingerichtet hatte. Ein Jahr später sagt Dümmer: "Hey, es sieht so aus, als würde diese Basisklasse nichts tun. Ich denke, ich werde es einfach entfernen ..." Und es verging eine Stunde meines Lebens, die ich niemals zurückbekommen werde. WARUM IST DAS ERFORDERLICH? Ich wünschte, ich hätte EF besser verstanden.
Wellspring
2

Ich erhalte den Fehler in einer anderen Situation und hier sind das Problem und die Lösung:

Ich habe 2 Klassen, die von derselben Basisklasse namens LevledItem abgeleitet sind:

public partial class Team : LeveledItem
{
   //Everything is ok here!
}
public partial class Story : LeveledItem
{
   //Everything is ok here!
}

Aber in ihrem DbContext habe ich einen Code kopiert, aber vergessen, einen der Klassennamen zu ändern:

public class MFCTeamDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Other codes here
        modelBuilder.Entity<LeveledItem>()
            .Map<Team>(m => m.Requires("Type").HasValue(ItemType.Team));
    }

public class ProductBacklogDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Other codes here
        modelBuilder.Entity<LeveledItem>()
            .Map<Team>(m => m.Requires("Type").HasValue(ItemType.Story));
    }

Ja, die zweite Karte <Team> sollte Karte <Story> sein. Und es hat mich einen halben Tag gekostet, es herauszufinden!

Cheny
quelle
2

Ich hatte ein ähnliches Problem, nicht genau die gleichen Bedingungen und dann habe ich diesen Beitrag gesehen . Hoffe es hilft jemandem. Anscheinend habe ich eines meiner EF-Entitätsmodelle als Basisklasse für einen Typ verwendet, der in meinem Datenbankkontext nicht als Datenbanksatz angegeben wurde. Um dieses Problem zu beheben, musste ich eine Basisklasse erstellen, die alle Eigenschaften der beiden Typen gemeinsam hatte und von der neuen Basisklasse zwischen den beiden Typen erbte.

Beispiel:

//Bad Flow
    //class defined in dbcontext as a dbset
    public class Customer{ 
       public int Id {get; set;}
       public string Name {get; set;}
    }

    //class not defined in dbcontext as a dbset
    public class DuplicateCustomer:Customer{ 
       public object DuplicateId {get; set;}
    }


    //Good/Correct flow*
    //Common base class
    public class CustomerBase{ 
       public int Id {get; set;}
       public string Name {get; set;}
    }

    //entity model referenced in dbcontext as a dbset
    public class Customer: CustomerBase{

    }

    //entity model not referenced in dbcontext as a dbset
    public class DuplicateCustomer:CustomerBase{

       public object DuplicateId {get; set;}

    }
KwakuCsc
quelle
1

Dieser Fehler tritt bei mir auf, weil ich Folgendes getan habe

  1. Ich habe den Spaltennamen der Tabelle in der Datenbank geändert
  2. (Ich habe nicht verwendet Update Model from database in Edmx ) Ich habe den Eigenschaftsnamen manuell umbenannt, um ihn an die Änderung im Datenbankschema anzupassen
  3. Ich habe einige Umgestaltungen vorgenommen, um den Namen der Eigenschaft in der Klasse so zu ändern, dass er mit dem Datenbankschema und den Modellen in Edmx übereinstimmt

Trotz alledem habe ich diesen Fehler bekommen

so what to do

  1. Ich habe das Modell aus Edmx gelöscht
  2. Rechtsklick und Update Model from database

Dadurch wird das Modell neu generiert und das Entity-Framework will nicht give you this error

hoffe das hilft dir

Basheer AL-MOMANI
quelle
1

Altes Q, aber für die Nachwelt ... es kommt auch vor (.NET Core 2.1), wenn Sie eine selbstreferenzierende Navigationseigenschaft ("Parent" oder "Children" desselben Typs) haben, der Name der Id-Eigenschaft jedoch nicht EF erwartet. Das heißt, ich hatte eine "Id" -Eigenschaft in meiner Klasse mit dem Namen WorkflowBaseund es gab eine Reihe verwandter untergeordneter Schritte, die ebenfalls vom Typ waren WorkflowBase, und es wurde immer wieder versucht, sie einer nicht vorhandenen "WorkflowBaseId" (dem Namen i) zuzuordnen Angenommen, es wird als natürlicher / konventioneller Standard bevorzugt. Ich hatte ausdrücklich zu konfigurieren , es zu benutzen HasMany(), WithOne()und HasConstraintName()ihm zu sagen , wie zu verfahren. Aber ich habe ein paar Stunden damit verbracht zu denken, dass das Problem darin besteht, den Primärschlüssel des Objekts 'lokal' zuzuordnen, was ich versucht habe, auf verschiedene Arten zu beheben, aber wahrscheinlich immer funktioniert hat.

tntwyckoff
quelle