Laden...

[erledigt] Entity Framework und SQL-Server: Primary Key ändern - Denkanstoß benötigt

Erstellt von m.grauber vor 13 Jahren Letzter Beitrag vor 13 Jahren 6.634 Views
M
m.grauber Themenstarter:in
343 Beiträge seit 2010
vor 13 Jahren
[erledigt] Entity Framework und SQL-Server: Primary Key ändern - Denkanstoß benötigt

verwendetes Datenbanksystem: <SQL-Server 2000-2008R2>

Hallo,

in einer Tabelle werden sehr viele Einträge erstellt und nach ca. 1 Tag wieder verworfen. Damit sich die Datenbank nicht zu sehr und schnell aufbläht, würde ich die alten Einträge beim "Austragen" markieren statt zu löschen. Später sollen diese für neue Einträge wiederverwendet werden.

Um eine Eindeutigkeit zu erzielen, müssen den neuen Einträgen auch neue ID´s gegeben werden. Nun habe ich aber das Problem, dass die ID der Primary Key ist und nicht geändert werden kann. Beim Ändern kommt verständlicherweise folgende Fehlermeldung:


  meinetabelle.id=100;  // Hier bereits Fehler
  e.SaveChanges()

Die Eigenschaft 'ID' ist Teil der Schlüsselinformationen des Objekts und kann nicht geändert werden.

Mir ist schon klar, dass ich den Schlüssel aus logischen Gründen so nicht ändern darf, doch wie kann ich dieses Problem umschiffen, ohne in einer weiteren Spalte eine weitere 'ID2' nutzen zu müssen?

Wenn irgendwie möglich würde ich gerne weiter mit SaveChanges() arbeiten, um nicht den gesamten Code umwerfen zu müssen.

Vielen Dank!

Mfg
Michael

PS: Ich stelle nur Fragen, wenn ich in Büchern, im Web und in Foren nichts gefunden habe. Dumme Fragen bitte ich zu entschuldigen!

:] VISUAL STUDIO 2017 + .NET FRAMEWORK 4.5 + SQL-Server 2012 :]

3.511 Beiträge seit 2005
vor 13 Jahren

Wenn du mit "verworfen" löschen meinst, verstehe ich das Problem nicht. Datensätze die gelöscht werden, geben intern ihre Pages wieder frei und können somit von neuen Daten überschrieben werden. Die DB sollte sich also bei konstanten Werten pro Tag von der Größe her nicht ändern.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

M
m.grauber Themenstarter:in
343 Beiträge seit 2010
vor 13 Jahren

Hallo Khalid,

danke für die schnelle Hilfe!

Du meinst also, dass mein Ansatz überhaupt nicht effizienter ist? Das wäre mir natürlich das liebste, da am Einfachsten. Jedoch verstehe ich es noch nicht ganz:

Die Tabelle besitzt ja einen Anfang, der an einer fixen Position auf dem Datenträger liegt. Alle angefügten Daten werden erst einmal (wenn Platz ist) dahinter geschrieben (wenn dort bereits etwas steht, dann an eine andere Stelle der Festplatte - Fragmentierung)

Wenn z. B. der 2. und der 3. Datensatz gelöscht werden und am Ende der Tabelle werden 2 Datensätze angefügt, werden diese doch nicht an der 2. und der 3. Stelle wieder eingefügt? (der Primary Key ist doch CLUSTERED) - Oder heißt dies, dass die wirklichen Daten schon an der 2. und der 3. Position wieder eingefügt werden, aber der zur Tabelle gehörige Index am Ende fortgeführt wird?

Abhängig davon kann das ja auch nochmals variieren, weil evtl. die Tabelle selbst nochmals größer ist, als der Platz, den sie benötigt.

D. h.

10000 Datensätze einfügen > 10000 Datensätze löschen > 10000 Datensätze erneut einfügen > usw. benötigt gleichviel Platz wie

10000 Datensätze einfügen > 10000 Datensätze überschreiben > usw.
?

Vielen Dank

Mfg
Michael

PS: Ich stelle nur Fragen, wenn ich in Büchern, im Web und in Foren nichts gefunden habe. Dumme Fragen bitte ich zu entschuldigen!

:] VISUAL STUDIO 2017 + .NET FRAMEWORK 4.5 + SQL-Server 2012 :]

16.835 Beiträge seit 2008
vor 13 Jahren

Eine ID/GUID ist ja aus Design sicht eigentlich vor allem dazu da, um Relationen einfacher zu beschreiben ( einmaliger Key, Eindeutigkeit etc etc.. ).
Wieso willst Du die ID also überschreiben?
Wieso löschst Du nicht einfach die #2 und machst dann mit der #3 weiter? Muss es mit Sinn wirklich lückenlos sein?

Um Dein Problem - auch ohne Sinn - zu lösen mach ein einfaches Update.
Bei mir ist es ebenfalls möglich ein Eintrag mit allen Relationen komplett zu ändern (quasi wie ein Ersetzen) - bis auf die ID und das Insert-Datum.
Damit beim SaveChanges() keine Exception aufgrund des attached-Status geworfen wird setze ich alle Werte der Properties auf modified, ändere anschließend alle relevanten Properties und führe dann SaveChanges() aus - einfach und (relativ) performant im Gegensatz zur Code-Variante.

3.511 Beiträge seit 2005
vor 13 Jahren

Auch ein Clustered Index fragmentiert. D.h. das die Daten immer an die Pages geschrieben werden, die als "Free Page" markiert sind. Wenn also neue Daten an die markierten Pages geschrieben werden, fragmentiert der Index. Aus dem Grund sollte man in regelmäßigen Abständen die Indizies defragmentieren.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

M
m.grauber Themenstarter:in
343 Beiträge seit 2010
vor 13 Jahren

Hallo Abt,

danke auch für Deine Hilfe!

Eine ID/GUID ist ja aus Design sicht eigentlich vor allem dazu da, um Relationen einfacher zu beschreiben ( einmaliger Key, Eindeutigkeit etc etc.. ).
Wieso willst Du die ID also überschreiben?

-> Ja, das ist mir klar. Die ID muss ich ändern, da die Datensätze, die aus der Tabelle herauswandern, diese ID bereits haben und damit eine Eindeutige zuweisung gegeben ist. Die neuen Einträge sollen ja nur den physikalischen Platz der alten Einträge bekommen, damit sich die Tabelle nicht zu sehr und schnell aufbläst. Dazu muss ich die ID und die anderen Feldinhalte durch andere Werte ersetzen.

Bei mir ist es ebenfalls möglich ein Eintrag mit allen Relationen komplett zu ändern (quasi wie ein Ersetzen) - bis auf die ID und das Insert-Datum.

-> Ja und das mit der ID ist genau mein Problem. Alle Werte können geändert werden, aber sobald die ID geändert wird, gibts einen Fehler.

**Wenn ich die ID per T-SQL-Befehl ändere, geht es ja auch problemlos. Nur ich möchte mir das sparen und gleich mit SaveChanges() ändern.

Langsam vermute ich, dass EF tatsächlich die ID aus meiner Klasse für den Updatebefehl verwendet und daher nicht änderbar machen darf. Ich hatte bisher angenommen, dass für den Key noch ein anderer Wert im "Hintergrund der Klasse" gespeichert ist. Weiß da jemand genaueres?**

Danke

Mfg
Michael

PS: Ich stelle nur Fragen, wenn ich in Büchern, im Web und in Foren nichts gefunden habe. Dumme Fragen bitte ich zu entschuldigen!

:] VISUAL STUDIO 2017 + .NET FRAMEWORK 4.5 + SQL-Server 2012 :]

16.835 Beiträge seit 2008
vor 13 Jahren

Hallo Abt,

danke auch für Deine Hilfe!

Eine ID/GUID ist ja aus Design sicht eigentlich vor allem dazu da, um Relationen einfacher zu beschreiben ( einmaliger Key, Eindeutigkeit etc etc.. ).
Wieso willst Du die ID also überschreiben?

-> Ja, das ist mir klar. Die ID muss ich ändern, da die Datensätze, die aus der Tabelle herauswandern, diese ID bereits haben und damit eine Eindeutige zuweisung gegeben ist. Die neuen Einträge sollen ja nur den physikalischen Platz der alten Einträge bekommen, damit sich die Tabelle nicht zu sehr und schnell aufbläst. Dazu muss ich die ID und die anderen Feldinhalte durch andere Werte ersetzen.

SQL Server 2008 R2 arbeitet mit XML-Files je Tabelle.
Ich kanns nicht mit Sicherheit sagen, da es schon etwas länger her ist, dass ich auf der Schulung war, aber ich meine, dass dies mit R2 einen deutlichen Performance-Schub in Sachen Belastung des Dateisystems mitgebracht hat und dieses Aufblähen und Fragmentieren minimiert wurde.

Bei mir ist es ebenfalls möglich ein Eintrag mit allen Relationen komplett zu ändern (quasi wie ein Ersetzen) - bis auf die ID und das Insert-Datum.

-> Ja und das mit der ID ist genau mein Problem. Alle Werte können geändert werden, aber sobald die ID geändert wird, gibts einen Fehler.

**Wenn ich die ID per T-SQL-Befehl ändere, geht es ja auch problemlos. Nur ich möchte mir das sparen und gleich mit SaveChanges() ändern.

Langsam vermute ich, dass EF tatsächlich die ID aus meiner Klasse für den Updatebefehl verwendet und daher nicht änderbar machen darf. Ich hatte bisher angenommen, dass für den Key noch ein anderer Wert im "Hintergrund der Klasse" gespeichert ist. Weiß da jemand genaueres?**

Du meinst den EntityKey?

Hast Du vielleicht einen Konfigurationsfehler oder Abhängigkeitsfehler im Mapping mit Deinem Key, vielleicht via FK? Als Primary und Identity-Key definiert?
Schau Dir mal Entity Framework 4 – N-Tier mit Self Tracking Entities an, besonders SetAllModified(). Auf dieser Basis kannst Du Dir ein Update aller Properties bauen.

Wie greifst Du denn auf Deine Datenbankfunktionen zu? Repository?

M
m.grauber Themenstarter:in
343 Beiträge seit 2010
vor 13 Jahren

Hallo Abt,

SQL Server 2008 R2 arbeitet mit XML-Files je Tabelle.

-> Das der Server intern mit xml-Files arbeitet kann ich fast nicht glauben. Dann müsste er ja gerade bei größeren Tabellen kreuzlahm werden.

Die Seite habe ich mir angesehen. Danke für den Link. Jedoch habe ich mich dafür entschieden, besser nicht so sehr zu tricksen. Workarounds könnten funktionieren, jedoch könnte man in späteren .NET Versionen böse Überraschungen erleben. Das will ich mir ersparen.

Da Khalid und auch Du nicht an ein derartiges Performance Problem glauben, bestärkt es mich, nun die Daten ordentlich zu löschen und neu zu erstellen. Ich kann das ja testen. Falls das später ein Performance- oder Platzproblem verursachen sollte, werde ich es später Umstellen.

Vielen Dank Euch beiden! 👍 👍

Grüße

Mfg
Michael

PS: Ich stelle nur Fragen, wenn ich in Büchern, im Web und in Foren nichts gefunden habe. Dumme Fragen bitte ich zu entschuldigen!

:] VISUAL STUDIO 2017 + .NET FRAMEWORK 4.5 + SQL-Server 2012 :]