Laden...

ADO.NET und SQLDependency

Erstellt von userid4106 vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.308 Views
U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 12 Jahren
ADO.NET und SQLDependency

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?

16.834 Beiträge seit 2008
vor 12 Jahren

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.

1.552 Beiträge seit 2010
vor 12 Jahren

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

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

C
80 Beiträge seit 2010
vor 12 Jahren

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.

2.891 Beiträge seit 2004
vor 12 Jahren

Für LINQ2SQL habe ich das in Datenbestand aus Datenbank automatisiert aktualisieren? mal ausprobiert.

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 12 Jahren

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?

2.891 Beiträge seit 2004
vor 12 Jahren

@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.

C
80 Beiträge seit 2010
vor 12 Jahren

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.

U
userid4106 Themenstarter:in
457 Beiträge seit 2006
vor 12 Jahren

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??