SQL Server 2008 R2
Hallo,
ich habe eine WPF Anwendung und beschäftige mich seit kurzem mit ADO.NET.
Nun stellt sich mir gerade folgende Frage. Wie bekomme ich Änderungen in der Datenbank mit?!
Ich muss zusehen, dass meine Anwendung immer aktuelle Daten hat. Sowas wie einen Refresh Button kann ich den Usern nicht zutrauen da sie die Daten enorm oft ändern werden. Deswegen soll das automatisch passieren.
Ich habe bisher folgendes getan. Visual Studios auf, neues WPF Projekt(was zum testen ist) erstellt und ein ADO.NET Entity Data Model hinzugefügt.
Wenn es eine Möglichkeit gibt, wo müsste ich mich am besten einhaken und WIE?
Um Änderungen mit zu bekommen nutzt man in der Regel SqlDependencies.
Mein letzter Stand ist jedoch, dass das von Dir eingesetzt Entity Framework dieses nicht unterstützt.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Generell unterstützt dies kein Framework.
Man muss sich selbst dazu kümmern dass sobald man eine Änderungsbenachrichtigung bekommt man diese Änderun richtig auswerted und gegebenfalls die vorhandenen Daten aktualisiert bzw neue Daten hinzufügt.
Gruß
Michael
Hallo Second Sun,
ich habe sowas entsprechend in unserer Firma schon umgesetzt. Diesen Teil müsstest du mit der SqlDependency-Klasse selbst übernehmen. Wenn du dabei Hilfe für das Konzept brauchst, kann ich dir gerne helfen.
Für LINQ2SQL habe ich das in Datenbestand aus Datenbank automatisiert aktualisieren? mal ausprobiert.
Moin Jungs,
als ich gestern Abend im Bett lag und mich noch etwas mit dem Problem beschäftigt habe, bin ich auf das hier gestoßen:
AutoRefresh für ADO.NET
P.S.: Das funktioniert wunderbar soweit.
Allerdings kann ich irgendwie nicht beurteilen, ob das eine sauberle Lösung ist.
@CSharperUser: Du könntest ja mal ein bisschen Code posten;-)
@dN!3L: Ich hab das nur ganz kurz überflogen und hab was von LINQ2SQL gelesen. Oder macht das in dem Fall keinen Unterschied?
@dN!3L: Ich hab das nur ganz kurz überflogen und hab was von LINQ2SQL gelesen. Oder macht das in dem Fall keinen Unterschied?
Im Prinzip ist es ein ähnliches Vorgehen wie beim AutoRefresh für ADO.NET. Die SqlConnection wird halt nur statt aus einem EF-EntityContext aus einem LINQ2SQL-DataContext geholt.
Ich habe auf die entsprechende Tabelle einen Trigger gesetzt, der in einer Art Report-Tabelle die entsprechenden Infos einträgt. Und nur auf diese Tabelle lausche ich mit der SqlDependency-Klasse. Bei einem Insert über den Trigger in die Tabelle erhalte ich dann ein Event. Dann hole ich den letzten Eintrag (über Zeitstempel) aus der Tabelle und interpretiere die Daten. Ich würde die SQLDependency niemals auf mehrere Tabelle lauschen lassen.
Verdammt, ich habe noch mal eine Frage.
Ich habe aus dem Link von oben nun diesen Code hier:
public static class ServiceBrokerUtility
{
private static List<string> connectionStrings = new List<string>();
private const string SqlDependencyCookie = "MS.SqlDependencyCookie";
private static ObjectContext _ctx;
private static RefreshMode _refreshMode;
private static IEnumerable _collection;
private static INotifyRefresh _notifyRefresh;
public static void AutoRefresh(this ObjectContext ctx, RefreshMode refreshMode, IEnumerable collection)
{
var csInEf = ctx.Connection.ConnectionString;
var csName = csInEf.Replace("name=", "").Trim();
var csForEf = ConfigurationManager.ConnectionStrings[csName].ConnectionString;
var newConnectionString = new EntityConnectionStringBuilder(csForEf).ProviderConnectionString;
if (!connectionStrings.Contains(newConnectionString))
{
connectionStrings.Add(newConnectionString);
SqlDependency.Start(newConnectionString);
}
ServiceBrokerUtility._ctx = ctx;
ServiceBrokerUtility._refreshMode = refreshMode;
ServiceBrokerUtility._collection = collection;
_notifyRefresh = collection as INotifyRefresh;
AutoRefresh();
}
public static void AutoRefresh()
{
var oldCookie = CallContext.GetData(SqlDependencyCookie);
try
{
var dependency = new SqlDependency();
CallContext.SetData(SqlDependencyCookie, dependency.Id);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
_ctx.Refresh(_refreshMode, _collection);
}
finally
{
CallContext.SetData(SqlDependencyCookie, oldCookie);
}
}
static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
AutoRefresh();
if (ServiceBrokerUtility._notifyRefresh != null)
{
Application.Current.Dispatcher.BeginInvoke((Action)(() => ServiceBrokerUtility._notifyRefresh.OnRefresh()));
}
}
}
public class AutoRefreshWrapper<T> : IEnumerable<T>, INotifyRefresh
where T : EntityObject
{
private IEnumerable<T> objectSet;
public AutoRefreshWrapper(ObjectSet<T> objectSet, RefreshMode refreshMode)
{
this.objectSet = objectSet;
objectSet.Context.AutoRefresh(refreshMode, this);
}
public IEnumerator<T> GetEnumerator()
{
return objectSet.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public void OnRefresh()
{
if (this.CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
}
public interface INotifyRefresh : INotifyCollectionChanged
{
void OnRefresh();
}
SonstigesFahrzeugstatus = new AutoRefreshWrapper<Fahrzeugstatus>(DispoplanContext.Fahrzeugstatus, RefreshMode.StoreWins);
SonstigesFahrzeugmarke = new AutoRefreshWrapper<Fahrzeugmarke>(DispoplanContext.Fahrzeugmarke, RefreshMode.StoreWins);
SonstigesFahrzeugstatus = new AutoRefreshWrapper<Fahrzeugstatus>(DispoplanContext.Fahrzeugstatus, RefreshMode.StoreWins);
SonstigesPersonenstatus = new AutoRefreshWrapper<Personenstatus>(DispoplanContext.Personenstatus, RefreshMode.StoreWins);
Funktioniert soweit auch ganz gut ABER es wird nur eine Tabelle aktualisiert. Sprich in dem Fall die "SonstigesPersonenstatus ". Also bei einer Initialisierung wie oben "übersieht" er alles bis auf das letzte. Wie muss ich den Kram nun aufbohren??