Entity Framework: Tabelle ohne Primärschlüssel


165

Ich habe eine vorhandene Datenbank, mit der ich eine neue App erstellen möchte EF4.0

In einigen Tabellen sind keine Primärschlüssel definiert, sodass beim Erstellen eines neuen Entitätsdatenmodells die folgende Meldung angezeigt wird:

The table/view TABLE_NAME does not have a primary key defined 
and no valid primary key could be inferred. This table/view has 
been excluded. To use the entity, you will need to review your schema, 
add the correct keys, and uncomment it.

Wenn ich sie verwenden und Daten ändern möchte, muss ich diesen Tabellen unbedingt eine PK hinzufügen, oder gibt es eine Problemumgehung, damit ich nicht muss?


21
Um Joe Celko zu zitieren: Wenn es keinen Primärschlüssel hat, ist es keine Tabelle . Warum um alles in der Welt sollte jemand eine "normale" Tabelle ohne Primärschlüssel erstellen? Fügen Sie einfach diese PK hinzu! Sie werden sie brauchen - eher früher als später ...
marc_s

4
Wenn es eine Ansicht ist, haben Sie einen Blick auf diesen Fall stackoverflow.com/a/10302066/413032
Davut Gürbüz

50
Es ist völlig richtig, dass nicht jede Tabelle einen Primärschlüssel benötigt. Nicht oft nützlich, aber gültig. Das Verwirren von EF ist ein guter Grund, nicht dass es viel kostet. ;-).
Suncat2000

25
Stellen Sie sich vor, ich kann die DB-Struktur in meinem Unternehmen nicht ändern und sie wurde von jemandem erstellt, der die Tabellenstruktur nicht ändert. Dieses Szenario ist möglich.
Tito

4
Genau hier sind wir. Wir müssen mit einer Oracle-Datenbank eines Drittanbieters arbeiten, die keine Primärschlüssel enthält.
David Brower

Antworten:


59

Der Fehler bedeutet genau das, was er sagt.

Selbst wenn Sie das umgehen könnten, vertrauen Sie mir, Sie wollen nicht. Die Anzahl der verwirrenden Fehler, die eingeführt werden könnten, ist erschütternd und beängstigend, ganz zu schweigen von der Tatsache, dass Ihre Leistung wahrscheinlich in die Knie gehen wird.

Umgehe das nicht. Korrigieren Sie Ihr Datenmodell.

EDIT: Ich habe gesehen, dass eine Reihe von Leuten diese Frage ablehnen. Das ist in Ordnung, nehme ich an, aber denken Sie daran, dass das OP nach der Zuordnung einer Tabelle ohne Primärschlüssel und nicht nach einer Ansicht gefragt hat . Die Antwort ist immer noch dieselbe. Unter dem Gesichtspunkt der Verwaltbarkeit, Datenintegrität und Leistung ist es eine schlechte Idee, die Notwendigkeit der EF zu umgehen, eine PK für Tabellen zu haben.

Einige haben kommentiert, dass sie das zugrunde liegende Datenmodell nicht reparieren können, da sie einer Drittanbieteranwendung zugeordnet sind. Das ist keine gute Idee, da sich das Modell unter Ihnen ändern kann. In diesem Fall möchten Sie wahrscheinlich eine Ansicht zuordnen, was wiederum nicht das ist, was das OP verlangt hat.


44
Stimmen Sie in gängigen Szenarien zu, aber in seltenen Szenarien wie der LOG-Tabelle müssen Sie nur so schnell wie möglich Datensätze einfügen. PK kann ein Problem sein, wenn die Eindeutigkeit überprüft und die Indizierung erfolgt. Auch wenn Ihre PK IDENTITY ist, ist die Rückgabe des generierten Werts an die EF ein weiteres Problem. stattdessen GUID verwenden? Generierungszeit und Indizierung / Sortierung sind ein weiteres Problem! ... SO IN einigen kritischen OLTP-Szenarien (wie der Protokollierung) ist es ein Punkt, keine PK zu haben, und es hat keinen positiven Punkt!
Mahmoud Moravej

5
@MahmoudMoravej: Verwechseln Sie zunächst nicht die Ideen zum Clustering von Indizes und Primärschlüsseln. Sie sind nicht dasselbe. Sie können sehr leistungsfähige Einfügungen in Tabellen mit gruppierten Angaben in IDENTITY-Spalten haben. Wenn Sie Probleme mit der Indexpflege haben, sollten Sie die Tabelle ordnungsgemäß partitionieren. Wenn Sie eine Tabelle ohne Clustered-Index belassen, können Sie sie auch nicht effektiv defragmentieren, um nach dem Löschen Speicherplatz zurückzugewinnen. Ich bedaure die arme Person, die versucht, Ihre Protokollierungstabelle abzufragen, wenn sie keine Indizes hat.
Dave Markle

148
"Fix your data model" ist keine echte Antwort. Manchmal müssen wir mit weniger als idealen Situationen leben, die wir nicht geschaffen haben und die wir nicht ändern können. Und wie @Colin sagte, gibt es eine Möglichkeit, genau das zu tun, was das OP verlangt hat.
TheSmurf

13
Das Ändern des Codes zur Erfüllung von EF ist eine Problemumgehung für sich. Nicht alle Tabellen benötigen einen Primärschlüssel und sollten auch nicht dazu gezwungen werden. ZB haben Sie ein Thema und es hat 0 oder viele Schlüsselwörter. Die Schlüsselworttabelle kann eine übergeordnete Themen-ID und ein entsprechendes Schlüsselwort enthalten. Zu sagen, dass ich meine Datenbank umbauen muss, weil EF mich dazu zwingt, ist lahm.
Mrchief

14
Dies sollte abgelehnt werden, da es die Frage nicht beantwortet. Wir müssen oft mit Datenbanken von Drittanbietern arbeiten, die nicht geändert werden können.
Kurren

104

Ich denke, das wird von Tillito gelöst:

Entity Framework und SQL Server-Ansicht

Ich werde seinen Eintrag unten zitieren:

Wir hatten das gleiche Problem und dies ist die Lösung:

Verwenden Sie ISNULL, um das Entity Framework zu zwingen, eine Spalte als Primärschlüssel zu verwenden.

Verwenden Sie NULLIF, um zu erzwingen, dass das Entity Framework keine Spalte als Primärschlüssel verwendet.

Eine einfache Möglichkeit, dies anzuwenden, besteht darin, die select-Anweisung Ihrer Ansicht in eine andere select-Anweisung zu verpacken.

Beispiel:

SELECT
  ISNULL(MyPrimaryID,-999) MyPrimaryID,
  NULLIF(AnotherProperty,'') AnotherProperty
  FROM ( ... ) AS temp

beantwortet 26. April 10 um 17:00 von Tillito


6
+1 Dies ist die richtige Antwort. In einer perfekten Welt wäre es großartig, alle alten Datenbanken so zu ändern, dass sie referenzielle Integrität aufweisen. In Wirklichkeit ist dies jedoch nicht immer möglich.
Dylan Hayes

9
Ich würde das nicht empfehlen. Insbesondere der ISNULL-Teil. Wenn EF zwei PKs gleich erkennt, werden die eindeutigen Datensätze möglicherweise nicht gerendert und stattdessen ein freigegebenes Objekt zurückgegeben. Das ist mir schon mal passiert.
Todd

@Todd - wie könnte das jemals passieren, wenn MyPrimaryID eine NOT NULL-Spalte ist?
JoeCool

@ JoeCool, nur weil es NICHT NULL ist, heißt das nicht, dass es einzigartig ist. Ich habe "DIESE LÖSUNG FUNKTIONIERT ..." positiv bewertet, denn unabhängig davon, in welchem ​​Kontext sie verwendet wird, können Sie sich auf die Einzigartigkeit verlassen. Wenn Sie jetzt darüber nachdenken, wird durch Löschen eines Datensatzes die "PK" der folgenden Datensätze effektiv geändert.
Todd

1
-1, da dies nicht die Konfiguration von Entity Framework / C # -Code für die Zuordnung zu einer Tabelle ohne Identitätsstart beantwortet. Software von Drittanbietern ist (aus irgendeinem Grund) so geschrieben.
Andrew Gray

27

Wenn ich sie verwenden und Daten ändern möchte, muss ich diesen Tabellen unbedingt eine PK hinzufügen, oder gibt es eine Problemumgehung, damit ich nicht muss?

Wenn Sie diese Frage beantworten und Entity Framework Core verwenden, müssen Sie diesen Tabellen nicht mehr unbedingt eine PK hinzufügen oder eine Problemumgehung durchführen. Seit EF Core 2.1 haben wir eine neue Funktion für Abfragetypen

Abfragetypen müssen verwendet werden für:

  • Dient als Rückgabetyp für Ad-hoc-FromSql () -Abfragen.
  • Zuordnung zu Datenbankansichten.
  • Zuordnung zu Tabellen, für die kein Primärschlüssel definiert ist.
  • Zuordnung zu im Modell definierten Abfragen.

Fügen Sie in Ihrem DbContext einfach die folgende Eigenschaft vom Typ hinzu, DbQuery<T>anstatt DbSet<T>wie unten beschrieben. Angenommen, Ihr Tabellenname lautet MyTable:

public DbQuery<MyTable> MyTables { get; set; }

1
Beste Antwort, wenn Sie EF Core verwenden!
Jay

17

Zusammengesetzte Schlüssel können auch mit der Entity Framework Fluent API erstellt werden

public class MyModelConfiguration : EntityTypeConfiguration<MyModel>
{
     public MyModelConfiguration()
     {
        ToTable("MY_MODEL_TABLE");
        HasKey(x => new { x.SourceId, x.StartDate, x.EndDate, x.GmsDate });
        ...
     }
}

In dieser Art von "manueller Zuordnung" stellte ich fest, dass die Angabe eines benutzerdefinierten Schlüssels, wie Sie zeigen, effektiv ist. Wenn Sie nicht über den Vorteil eines zusammengesetzten Schlüssels verfügen (wie in dieser Antwort gezeigt), können Sie einen modelBuilder.Entity<T>()Kettenaufruf mit .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)diesen ach so speziellen Schlüsseln versehen, die nicht natürlich oder zusammengesetzt sind, aber als verlässlich angesehen werden können auf einzigartig zu sein (normalerweise sowieso.)
Andrew Gray

5

In meinem Fall musste ich eine Entität einer Ansicht zuordnen, die keinen Primärschlüssel hatte. Außerdem durfte ich diese Ansicht nicht ändern. Glücklicherweise hatte diese Ansicht eine Spalte, die eine eindeutige Zeichenfolge war. Meine Lösung bestand darin, diese Spalte als Primärschlüssel zu markieren:

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[StringLength(255)]
public string UserSID { get; set; }

Betrogene EF. Hat perfekt funktioniert, niemand hat es bemerkt ... :)


nein .. Es wird die UserIDSpalte erstellt, wenn Sie den Code First-Ansatz verwenden ..!
Deepak Sharma

1
Sie haben EF nicht betrogen. Sie haben gerade befohlen, die ItentityFunktion auszuschalten . Wenn ich richtig liege, wird im Grunde immer noch eine UserIDSpalte für Sie als PK erstellt, aber die wird nicht automatisch erhöht, UserIDwenn Sie einen neuen Datensatz erstellen, wie dies standardmäßig der Fall wäre. Außerdem müssen Sie immer noch unterschiedliche Werte beibehalten UserID.
Celdor

1
@Celdor UserSID ist eine Zeichenfolge, die niemals "automatisch erhöht" wird. Wenn es sich um eine ganzzahlige Identitätsspalte handelt, wird sie von der Datenbank beim Einfügen erhöht, nicht beim Entity Framework.
Reggaeguitar

4

EF benötigt keinen Primärschlüssel in der Datenbank. In diesem Fall konnten Sie keine Entitäten an Ansichten binden.

Sie können die SSDL (und die CSDL) ändern, um ein eindeutiges Feld als Primärschlüssel anzugeben. Wenn Sie kein einzigartiges Feld haben, dann glaube ich, dass Sie abgespritzt sind. Aber Sie sollten wirklich ein eindeutiges Feld (und eine PK) haben, sonst werden Sie später auf Probleme stoßen.

Erick


Dies vermeidet den ISNULL-Hack. Abhängig von der Situation können jedoch andere Antworten erforderlich sein. Ich habe das Gefühl, dass einige Datentypen beispielsweise für eine PK in EF nicht unterstützt werden.
Todd

3

Einen nutzlosen Identitätsschlüssel zu haben ist manchmal sinnlos. Ich finde, wenn die ID nicht verwendet wird, warum sie hinzufügen? Entity verzeiht dies jedoch nicht so sehr, daher ist es am besten, ein ID-Feld hinzuzufügen. Selbst wenn es nicht verwendet wird, ist es besser, als sich mit den unaufhörlichen Fehlern von Entity bezüglich des fehlenden Identitätsschlüssels zu befassen.


3

DIESE LÖSUNG FUNKTIONIERT

Sie müssen nicht manuell zuordnen, auch wenn Sie keine PK haben. Sie müssen dem EF nur mitteilen, dass eine Ihrer Spalten Index ist und die Indexspalte nicht nullwertfähig ist.

Dazu können Sie Ihrer Ansicht eine Zeilennummer mit der folgenden isNull-Funktion hinzufügen

select 
    ISNULL(ROW_NUMBER() OVER (ORDER BY xxx), - 9999) AS id
from a

ISNULL(id, number) ist hier der entscheidende Punkt, da er dem EF mitteilt, dass diese Spalte ein Primärschlüssel sein kann


2
Ich würde den ISNULL-Teil allerdings nicht vorschlagen. Wenn EF zwei PKs gleich erkennt, wird der eindeutige Datensatz möglicherweise nicht gerendert und stattdessen ein freigegebenes Objekt zurückgegeben. Das ist mir schon mal passiert.
Todd

1
Sie müssen isnull verwenden, sonst glaubt EF nicht, dass es nicht nullbar ist.
Archlight

2

Die obigen Antworten sind richtig, wenn Sie wirklich keine PK haben.

Wenn es jedoch einen gibt, der jedoch nicht mit einem Index in der Datenbank angegeben ist und Sie die Datenbank nicht ändern können (ja, ich arbeite in Dilberts Welt), können Sie die Felder manuell als Schlüssel zuordnen.


2

Dies ist nur eine Ergänzung zu @Erick T's Antwort. Wenn es keine einzelne Spalte mit eindeutigen Werten gibt, besteht die Problemumgehung darin, einen zusammengesetzten Schlüssel wie folgt zu verwenden:

[Key]
[Column("LAST_NAME", Order = 1)]
public string LastName { get; set; }

[Key]
[Column("FIRST_NAME", Order = 2)]
public string FirstName { get; set; }

Auch dies ist nur eine Problemumgehung. Die wirkliche Lösung besteht darin, das Datenmodell zu reparieren.


2

Dies ist vielleicht zu spät, um zu antworten ... aber ...

Wenn eine Tabelle keinen Primärschlüssel hat, müssen nur wenige Szenarien analysiert werden, damit die EF ordnungsgemäß funktioniert. Die Regel lautet: EF arbeitet mit Tabellen / Klassen mit Primärschlüssel. So macht es Tracking ...

Angenommen, Ihre Tabelle 1. Datensätze sind eindeutig: Die Eindeutigkeit wird durch eine einzelne Fremdschlüsselspalte festgelegt: 2. Datensätze sind eindeutig: Die Eindeutigkeit wird durch eine Kombination mehrerer Spalten erstellt. 3. Datensätze sind nicht eindeutig (größtenteils *).

Für die Szenarien 1 und 2 können Sie der OnModelCreating-Methode des DbContext-Moduls die folgende Zeile hinzufügen: modelBuilder.Entity (). HasKey (x => new {x.column_a, x.column_b}); // so viele Spalten wie nötig, um Datensätze eindeutig zu machen.

Für das Szenario Nr. 3 können Sie nach dem Studium der Tabelle weiterhin die oben genannte Lösung (Nr. 1 + Nr. 2) verwenden (* was alle Datensätze sowieso einzigartig macht). Wenn Sie ALLE Spalten einschließen müssen, um alle Datensätze eindeutig zu machen, möchten Sie möglicherweise eine Primärschlüsselspalte zu Ihrer Tabelle hinzufügen. Wenn diese Tabelle von einem Drittanbieter stammt, klonen Sie diese Tabelle in Ihre lokale Datenbank (über Nacht oder so oft wie nötig), wobei die Primärschlüsselspalte über Ihr Klonskript beliebig hinzugefügt wird.


1
  1. Ändern Sie die Tabellenstruktur und fügen Sie eine Primärspalte hinzu. Aktualisieren Sie das Modell
  2. Ändern Sie die EDMX-Datei im XML-Editor und versuchen Sie, eine neue Spalte unter dem Tag für diese bestimmte Tabelle hinzuzufügen (FUNKTIONIERT NICHT).
  3. Anstatt eine neue Primärspalte zum Beenden der Tabelle zu erstellen, werde ich einen zusammengesetzten Schlüssel erstellen, indem ich alle vorhandenen Spalten einbeziehe ( ARBEITET ).

Entity Framework: Hinzufügen einer Datentabelle ohne Primärschlüssel zum Entitätsmodell.


Ich habe den Composite-Key-Ansatz mit EF 4.0 ausprobiert und er hat nicht funktioniert.
Ralph Willgoss

Dieser Ansatz hat perfekt für mich funktioniert, kann ein Schmerz sein, mit Legacy-Systemen "manchmal" zu arbeiten ...
pinmonkeyiii

1

Update auf @CodeNotFound die Antwort .

In EF Core 3.0 DbQuery<T>ist veraltet, stattdessen sollten Sie Keyless-Entitätstypen verwenden, die angeblich dasselbe tun. Diese werden mit der ModelBuilder- HasNoKey()Methode konfiguriert . Führen Sie dies in Ihrer DbContext-Klasse aus

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<YourEntityType>(eb =>
        {
            eb.HasNoKey();
        });

}

Es gibt jedoch Einschränkungen, insbesondere:

  • Werden niemals auf Änderungen im DbContext verfolgt und daher niemals in die Datenbank eingefügt, aktualisiert oder gelöscht.
  • Unterstützt nur eine Teilmenge der Navigationszuordnungsfunktionen, insbesondere:
    • Sie dürfen niemals als Hauptziel einer Beziehung fungieren.
    • Sie haben möglicherweise keine Navigation zu eigenen Entitäten
    • Sie können nur Referenznavigationseigenschaften enthalten, die auf reguläre Entitäten verweisen.
    • Entitäten dürfen keine Navigationseigenschaften für schlüssellose Entitätstypen enthalten.

Dies bedeutet, dass für die Frage von

Wenn ich sie verwenden und Daten ändern möchte, muss ich diesen Tabellen unbedingt eine PK hinzufügen, oder gibt es eine Problemumgehung, damit ich nicht muss?

Sie können Daten auf diese Weise nicht ändern - Sie können sie jedoch lesen. Man könnte sich jedoch vorstellen, eine andere Methode (z. B. ADO.NET, Dapper) zu verwenden, um Daten zu ändern - dies könnte eine Lösung in Fällen sein, in denen Sie selten nicht gelesene Vorgänge ausführen müssen und in den meisten Fällen dennoch bei EF Core bleiben möchten.

Wenn Sie wirklich mit Heap-Tabellen (ohne Schlüssel) arbeiten müssen / möchten, sollten Sie EF in den Hintergrund rücken und auf andere Weise mit Ihrer Datenbank kommunizieren.


0

Aus praktischer Sicht sollte jede Tabelle - selbst eine denormalisierte Tabelle wie eine Lagertabelle - einen Primärschlüssel haben. Andernfalls sollte es mindestens einen eindeutigen, nicht nullwertfähigen Index haben.

Ohne einen eindeutigen Schlüssel können (und werden) doppelte Datensätze in der Tabelle angezeigt werden, was sowohl für ORM-Ebenen als auch für das grundlegende Verständnis der Daten sehr problematisch ist. Eine Tabelle mit doppelten Datensätzen ist wahrscheinlich ein Symptom für schlechtes Design.

Zumindest sollte die Tabelle mindestens eine Identitätsspalte haben. Das Hinzufügen einer automatisch generierenden ID-Spalte dauert in SQL Server ca. 2 Minuten und in Oracle ca. 5 Minuten. Für diesen zusätzlichen Aufwand werden viele, viele Probleme vermieden.


Meine Anwendung befindet sich in einer Data Warehouse-Umgebung (mit Oracle) und Sie haben mich überzeugt, die 5 Minuten durchzugehen, um einen Index hinzuzufügen. Es dauert wirklich nur 5 Minuten (oder etwas länger, wenn Sie nachschlagen oder ETLs ändern müssen).
Trent

0

Wir sind auch auf dieses Problem gestoßen, und obwohl wir eine Spalte mit Nullen hatten, war es wichtig, dass wir eine abhängige Spalte hatten, die keine Nullen hatte, und dass die Kombination dieser beiden Spalten eindeutig war.

Um die Antwort von Pratap Reddy zu zitieren, hat es für uns gut funktioniert.




-8

Die Tabelle muss nur eine Spalte enthalten, die keine Nullen zulässt

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.