3 Stimmen

Arbeiten mit MvvM und Gleichzeitigkeit

Ich entwickle eine Anwendung mit WPF und MvvM, geschrieben in C#. Ich bin immer noch ein Anfänger mit der einige der Konzepte von MvvM und die Entität Rahmen. Ich habe, wie es scheint, alles funktioniert, außer das Problem der Gleichzeitigkeit. Ich arbeitete durch diese Microsoft-Artikel und es hat bei mir nicht funktioniert. Wie bei der MvvM-Struktur habe ich also eine Modell- und Entitätsdatei namens BackflowManagementEntities . Ich habe dann ein Repository, das die Aktualisierung für einen Prüfer übernimmt. Ich eingefügt versuchen und fangen hier für die Prüfung und kein Glück.

private BackflowManagementEntities dbContext;
internal void SaveChanges()
{
      try
      {
           dbContext.SaveChanges(); 
      }
      catch (DBConcurrencyException ex)
      {
           Console.WriteLine("Concurrency Exception : " + ex.Message);
      }
}

Ich habe also eine dreiteilige Frage:

  1. Dies ist der einzige Ort, den ich denken kann, dass ich die Gleichzeitigkeitsprüfung implementieren sollte. Bitte lassen Sie mich wissen, wenn ich falsch liege.
  2. Ist dies die richtige Ausnahme/Weise, um den Gleichzeitigkeitsfehler zu überprüfen? Ich verstehe, wie man mit dem Gleichzeitigkeitsfehler umgeht, ich weiß nur nicht, wie man ihn abfängt.
  3. Gibt es irgendeine Quelle, die Sie mir empfehlen würde, auf den Umgang mit und das Abfangen von Gleichzeitigkeitsausnahmen zu lesen?

3voto

Dean Kuga Punkte 11481

Überprüfen Sie Speichern von Änderungen und Verwaltung der Gleichzeitigkeit MSDN Artikel...

Standardmäßig wird das Entity Framework ein optimistisches Gleichzeitigkeits Modell. Das bedeutet, dass Sperren nicht auf Daten in der Datenquelle gehalten werden zwischen der Abfrage der Daten und der die Daten aktualisiert werden. Das Entity Framework speichert Objektänderungen in der Datenbank ohne Prüfung auf Gleichzeitigkeit. Für Entitäten, die möglicherweise ein hohes Maß an Gleichzeitigkeit auftreten kann, empfehlen wir, dass die Entität eine Eigenschaft in der konzeptionellen Schicht mit einem Attribut von ConcurrencyMode="fixed", wie im folgenden Beispiel gezeigt dem folgenden Beispiel:

Alle widersprüchlichen Änderungen führen zu einer OptimisticConcurrencyException .

Weitere Informationen finden Sie unter Wie man: Verwalten der Datengleichzeitigkeit im Objektkontext .

Kurz gesagt, ändern Sie die ConcurrencyMode zu fixieren und die OptimisticConcurrencyException Ausnahme...

1voto

suulisin Punkte 1405

Ich weiß, ich bin sehr spät zu diesem, aber dies ist etwas, das eine Menge Entwickler Gesicht whiles Entwicklung Multi-Thread-Anwendung mit Entity Framework und wpf. Hier sind ein paar Dinge, die Sie beachten müssen

  1. ) können Sie vom Hintergrund-Thread nicht auf den UI-Thread zugreifen.
  2. ) Dbcontext ist nicht thread-sicher, so dass die Verwendung in einem Multithreading in einer Multi-Thread-Umgebung zu Problemen führen kann, wenn nicht darauf geachtet wird

Hier ist also die Art und Weise, wie ich dieses Problem gelöst habe: Meine Lösung folgt dem abstrakten Repository-Muster. Die beteiligten Klassen und Schnittstellen sind:

  1. DataRepository und IDataRepository

  2. Student und IStudent

  3. StudentViewModel

  4. EntityBase

Dies ist IDataRepository

 public interface IDataRepository 
        {
            void AddAsync<T>(T entity, Action<T>callBack,Action<Exception>exceptionCallback=null) where T : EntityBase;
            void DeleteAsync<T>(int[] ids, Action callBack, Action<Exception> exceptionCallback = null) where T : EntityBase;
            void UpdateAsync<T>(T entity, Action<T> callBack, Action<Exception> exceptionCallback = null) where T : EntityBase;
            void FindAsync<T>(int id, Action<T> callBack, Action<Exception> exceptionCallback = null) where T : EntityBase;
           void FindAsync<T>(Action<List<T>> callBack,Expression<Func<T, bool>> predicate=null, int? pageIndex=0, int? pageSize=20, params Expression<Func<T, object>>[] includes) where T : EntityBase;
        }

Dies ist DataRepository

 public class Repository<TContext>: IDataRepository

       where TContext:DbContext,new ()
   {

        protected static void ExecuteAsync<T>(Func<List<T>> task, Action<List<T>> callback, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
            var worker = new BackgroundWorker();
            worker.DoWork += (s, e) =>
            {
                e.Result = task();
            };
            worker.RunWorkerCompleted += (s, e) =>
            {
                if (e.Error == null && callback != null)
                    callback((List<T>)e.Result);
                else if (e.Error != null && exceptionCallback != null)
                    exceptionCallback(e.Error);
            };
            worker.RunWorkerAsync();
        }

        protected static void ExecuteAsync<T>(Func<T> task, Action<T> callback, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
            var worker = new BackgroundWorker();
            worker.DoWork += (s, e) =>
            {
                e.Result = task();
            };
            worker.RunWorkerCompleted += (s, e) =>
            {
                if (e.Error == null && callback != null)
                    callback((T)e.Result);
                else if (e.Error != null && exceptionCallback != null)
                    exceptionCallback(e.Error);
            };
            worker.RunWorkerAsync();
        }

        protected static void ExecuteAsync(Action task, Action callback, Action<Exception> exceptionCallback = null)
        {
            var worker = new BackgroundWorker();
            worker.DoWork += (s, e) =>
            {
               task();
            };
            worker.RunWorkerCompleted += (s, e) =>
            {
                if (e.Error == null && callback != null)
                    callback();
                else if (e.Error != null && exceptionCallback != null)
                    exceptionCallback(e.Error);
            };
            worker.RunWorkerAsync();
        }

        public void AddAsync<T>(T entity, Action<T> callBack, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
            ExecuteAsync(() =>
            {
                using (var context = new TContext())
                {
                   var addedEntity = context.Set<T>().Add(entity);
                    context.SaveChanges();
                    return addedEntity;
                }
            },callBack,exceptionCallback);

       }

       public void DeleteAsync<T>(int[] ids, Action callBack, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
            ExecuteAsync(() =>
            {
                using (var context = new TContext())
                {
                   var entitiesToRemove = context.Set<T>().Where(x => ids.Contains(x.Id)).ToList();
                    foreach (var entity in entitiesToRemove)
                    {
                        context.Entry(entity).State=EntityState.Deleted;
                    }
                    context.SaveChanges();                    
                }
            },callBack, exceptionCallback);
        }

       public void UpdateAsync<T>(T entity, Action<T> callBack, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
           ExecuteAsync(() =>
           {
               using (var context=new TContext())
               {
                 context.Entry(entity).State=EntityState.Modified;
                   context.SaveChanges();
                   var updatedEntity = context.Set<T>().Find(entity.Id);
                   return updatedEntity;
               }
           },callBack,exceptionCallback);
       }

       public void FindAsync<T>(int id, Action<T> callBack, Action<Exception> exceptionCallback = null) where T : EntityBase
        {
           ExecuteAsync(() =>
           {
               using (var context=new TContext())
               {
                   var entity = context.Set<T>().Find(id);
                   return entity;
               }
           },callBack,exceptionCallback);
       }

       public void FindAsync<T>(Action<List<T>> callBack, Expression<Func<T, bool>> predicate=null, int? pageIndex = 0, int? pageSize = 20, params Expression<Func<T, object>>[] includes) where T : EntityBase
        {
           ExecuteAsync(() =>
           {
               using (var context=new TContext())
               {
                   var query = context.Set<T>().AsQueryable();

                   if (includes != null)
                   {
                       query = includes.Aggregate(query, (current, include) => current.Include(include));
                   }
                   if (predicate != null)
                       query = query.Where(predicate);

                   var offset = (pageIndex ?? 0) * (pageSize ?? 15);
                   query = query.OrderBy(x=>x.Id).Skip(offset).Take(pageSize ?? 15);

                   return query.ToList();
               } 
           },callBack);
       }
   }

dies ist das Student Repository und IStudentRepository

  public interface IStudentRepository:IDataRepository
    {
         void AddGuardian(Gurdian gurdian, int studentId,Action<Student> callBack);
         void SaveStudent(Student student, Gurdian gurdian,Action<Student>callBack);         
         void GetPrimaryGurdian(int studentId,Action<Gurdian> callBack );

    }

[Export(typeof(IStudentRepository))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class StudentRepository : Repository<StudentContext>, IStudentRepository
    {
        public void AddGuardian(Gurdian gurdian, int studentId, Action<Student> callBack)
        {
           FindAsync<Student>(studentId, (student) =>
           {
               student.Gurdians.Add(gurdian);
               UpdateAsync(student, callBack);
           });
        }

        public void SaveStudent(Student student, Gurdian gurdian, Action<Student> callBack)
        {
          student.Gurdians.Add(gurdian);
            AddAsync(student, callBack);
        }

        public void GetPrimaryGurdian(int studentId, Action<Gurdian> callBack)
        {
           FindAsync<Student>(studentId,(student)=> { callBack(student.PrimaryGurdian); });
        }
    }

Dann schließlich Ihr viewModel

[Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class StudentViewModel : ViewModelBase
    {        

        private readonly IStudentRepository _repository;

        [ImportingConstructor]
        public StudentViewModel()
        {

            _repository =new StudentRepository();

            Student = new Student();         
            SaveStudentCommand = new RelayCommand(OnStudentSaveExcute, CanSaveStudent);

        }

        #region Properties
        private Student _student;

        public Student Student
        {
            get { return _student; }
            set { _student = value; OnPropertyChanged(() => Student); }
        }

        private ObservableCollection<Student> _students = new ObservableCollection<Student>();

        public ObservableCollection<Student> Students
        {
            get { return _students; }
            set { _students = value; }
        }

        #endregion

        #region Commands
        public ICommand SaveStudentCommand { get; set; }

        private void OnStudentSaveExcute()
        {

            _repository.SaveStudent(Student,Gurdian, (student) =>
            {
                _students.Add(student);
            });

        }

        #endregion

        private  void LoadStudents()
        {

            _repository.FindAsync<Student>((students) =>
            {
                foreach(var student in students)
                _students.Add(student);
            });
        }

    }

public class EntityBase{
public int get{get;set;}
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X