Das ProblemWenn ich Daten in meinem LINQtoSQL DataContext ändere und diese Änderungen an die Datenbank senden möchte kommt es zu ChangeConflicts. Wie kann ich diese behandeln? Die LösungZunächst legen Sie ein Windows Forms Projekt an. Fügen Sie dem Projekt dann über die Item Templates ein „LINQ to SQL Classes“ Element hinzu und nennen dieses Element „Northwind.dbml“. Laden Sie sich anschließend die Northwind Datenbank herunter (http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en) und fügen Sie diese Datenbank zu Ihrer SQL Server (Express) Installation hinzu. In Visual Studio fügen Sie nun eine Verbindung zu dieser Datenbank über die Schaltflächen des Datenbank Explorers hinzu. Anschließend öffnen Sie die eben erstellte Northwind.dbml per Doppelklick im Projektmappenexplorer, worauf hin der OR Designer von Visual Studio öffnet. Ziehen Sie nun die Tabelle „Customers“ per Drag&Drop auf die Designeroberfläche:
Im Hintergrund erstellt Visual Studio nun das Objektmodell für die ausgewählte Tabelle und den DataContext über den die Verbindung zur Datenbank hergestellt wird und die CRUD Operationen abgesetzt werden können. Um nun auf den erstellten DataContext zugreifen zu können, legen Sie in der Main Methode zwei Instanzen dieser Klasse an:
Dim db As New NorthwindDataContext()
Dim db2 As New NorthwindDataContext
Fügen Sie nun der Main Methode die folgenden Zeilen ein:
'Teil 1 - Das manuelle Behandeln von Konflikten
db.Customers.First().CompanyName = "Company Eins"
db.Customers.First().ContactName = "Name Eins"
db2.Customers.First().ContactName = "Name Zwei"
db2.Customers.First().ContactTitle = "Verkauf"
db.SubmitChanges()
db2.SubmitChanges()
Wenn Sie diesen Code ausführen, werden Sie eine Fehlermeldung erhalten, da über zwei unterschiedliche Verbindungen Änderungen am gleichen Datensatz gemacht wurden. In dem Moment, in dem die Änderungen über „db2“ an die Datenbank gesendet werden sollen, stellt der DataContext fest, dass sein Datenbestand nicht mehr aktuell ist und wirft eine Exception. Um diese ChangeConflicts zu behandeln ersetzen Sie die Zeile mit „db2.SubmitChanges()“ durch den folgenden Code:
Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Catch ex As ChangeConflictException
For Each occ As ObjectChangeConflict In db2.ChangeConflicts
For Each mcc As MemberChangeConflict In occ.MemberConflicts
Console.WriteLine("1. Originalwert" & mcc.OriginalValue)
Console.WriteLine("2. Datenbankwert" & mcc.DatabaseValue)
Console.WriteLine("3. Aktueller Wert" & mcc.CurrentValue)
Select Case Console.ReadLine
Case "1"
mcc.Resolve(mcc.OriginalValue)
Case "2"
mcc.Resolve(mcc.DatabaseValue)
Case "3"
mcc.Resolve(mcc.CurrentValue)
Case Else
mcc.Resolve(mcc.CurrentValue)
End Select
Next
Next
End Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Der obige Code befragt nun den Nutzer bei jedem Datenfeld, welches von einem ChangeConflict betroffen ist, welcher Wert (OriginalValue, DatabaseValue oder CurrentValue) in die Datenbank geschrieben werden soll. Der OriginalValue ist dabei derjenige Wert, den das Feld zu dem Zeitpunkt des erzeugen des DataContextes hatte. Der DatabaseValue ist der Wert, der aktuell in der Datenbank steht. Der CurrentValue ist der Wert, der durch die Änderungen im DataContext (in unserem Fall also das Zuweisen von CompanyName, ContactName und ContactTitle) zustande gekommen sind. Um Konflikte automatisch zu lösen ersetzen Sie einfach den Try-Catch Block von eben durch:
Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Catch ex As ChangeConflictException
db2.Refresh(RefreshMode.OverwriteCurrentValues, db2.Customers)
End Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Der obige Code bewirkt, dass alle Felder, welche konfliktbehaftet waren, auf die Werte aus der Datenbank zurückgesetzt werden. Ändert man den „RefreshMode“ auf „KeepCurrentValues“, so werden die konfliktbehafteten Felder beim nächsten „SubmitChanges“ in der Datenbank mit denen aus dem DataContext überschrieben. Setzt man den „RefreshMode“ auf „KeepChanges“ und führt danach „SubmitChanges“ aus, so werden diejenigen Felder, die im DataContext geändert wurden in die Datenbank übernommen und alle anderen Felder im DataContext werden auf den aktuellen Wert aus der Datenbank aktualisiert. Der CodeVisual Basic
Imports System.Data.Linq
Module Module1
Dim db As New NorthwindDataContext
Dim db2 As New NorthwindDataContext
Sub Main()
'Teil 1 - Das manuelle Behandeln von Konflikten
db.Customers.First().CompanyName = "Company Eins"
db.Customers.First().ContactName = "Name Eins"
db2.Customers.First().ContactName = "Name Zwei"
db2.Customers.First().ContactTitle = "Verkauf"
db.SubmitChanges()
Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Catch ex As ChangeConflictException
For Each occ As ObjectChangeConflict In db2.ChangeConflicts
For Each mcc As MemberChangeConflict In occ.MemberConflicts
Console.WriteLine("1. Originalwert" & mcc.OriginalValue)
Console.WriteLine("2. Datenbankwert" & mcc.DatabaseValue)
Console.WriteLine("3. Aktueller Wert" & mcc.CurrentValue)
Select Case Console.ReadLine
Case "1"
mcc.Resolve(mcc.OriginalValue)
Case "2"
mcc.Resolve(mcc.DatabaseValue)
Case "3"
mcc.Resolve(mcc.CurrentValue)
Case Else
mcc.Resolve(mcc.CurrentValue)
End Select
Next
Next
End Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
'Teil 2 - Das automatische Behandeln von Konflikten
db.Customers.First().CompanyName = "Company Eins"
db.Customers.First().ContactName = "Name Eins"
db2.Customers.First().ContactName = "Name Zwei"
db2.Customers.First().ContactTitle = "Verkauf"
db.SubmitChanges()
Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
Catch ex As ChangeConflictException
db2.Refresh(RefreshMode.KeepChanges, db2.Customers)
End Try
db2.SubmitChanges(ConflictMode.ContinueOnConflict)
End Sub
End Module
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
namespace ChangeConflicts_in_LINQ_behandeln
{
static class Program
{
static NorthwindDataContext db = new NorthwindDataContext();
static NorthwindDataContext db2 = new NorthwindDataContext();
public static void Main()
{
//Teil 1 - Das manuelle Behandeln von Konflikten
db.Customers.First().CompanyName = "Company Eins";
db.Customers.First().ContactName = "Name Eins";
db2.Customers.First().ContactName = "Name Zwei";
db2.Customers.First().ContactTitle = "Verkauf";
db.SubmitChanges();
try
{
db2.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException ex)
{
foreach (ObjectChangeConflict occ in db2.ChangeConflicts)
{
foreach (MemberChangeConflict mcc in occ.MemberConflicts)
{
Console.WriteLine("1. Originalwert" + mcc.OriginalValue);
Console.WriteLine("2. Datenbankwert" + mcc.DatabaseValue);
Console.WriteLine("3. Aktueller Wert" + mcc.CurrentValue);
switch (Console.ReadLine())
{
case "1":
mcc.Resolve(mcc.OriginalValue);
break;
case "2":
mcc.Resolve(mcc.DatabaseValue);
break;
case "3":
mcc.Resolve(mcc.CurrentValue);
break;
default:
mcc.Resolve(mcc.CurrentValue);
break;
}
}
}
}
db2.SubmitChanges(ConflictMode.ContinueOnConflict);
//Teil 2 - Das automatische Behandeln von Konflikten
db.Customers.First().CompanyName = "Company Eins";
db.Customers.First().ContactName = "Name Eins";
db2.Customers.First().ContactName = "Name Zwei";
db2.Customers.First().ContactTitle = "Verkauf";
db.SubmitChanges();
try
{
db2.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException ex)
{
db2.Refresh(RefreshMode.KeepChanges, db2.Customers);
}
db2.SubmitChanges(ConflictMode.ContinueOnConflict);
}
}
}
|