Рабочий MvvM и параллелизм - PullRequest
2 голосов
/ 08 февраля 2011

Я занимаюсь разработкой приложения с использованием WPF и MvvM, написанного на C #.Я все еще начинающий с некоторыми концепциями MvvM и структурой сущностей.У меня есть то, что кажется, что все работает, кроме проблемы параллелизма.Я работал над этой статьей Microsoft , и она не сработала для меня.Итак, как и структура MvvM, у меня есть файл модели и сущностей с именем BackflowManagementEntities .Затем у меня есть хранилище, которое обрабатывает обновление для тестера.Я вставил попробовать и поймать здесь для тестирования и не повезло.

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

Так что у меня есть вопрос из трех частей:

  1. Это единственное место, где я могу думать, что я долженосуществлять проверку параллелизма.Пожалуйста, дайте мне знать, если я ошибаюсь.
  2. Это правильное исключение / способ проверки на наличие ошибки параллелизма?Я понимаю, как справиться с ошибкой параллелизма, но я просто не знаю, как ее перехватить.
  3. Есть ли какой-нибудь источник, который вы бы мне порекомендовали прочитать о работе с исключениями параллелизма?

Ответы [ 2 ]

3 голосов
/ 08 февраля 2011

Оформить Сохранение изменений и управление параллелизмом Статья MSDN ...

По умолчанию Entity Framework реализует оптимистичный параллелизм модель. Это означает, что замки не хранится на данных в источнике данных между тем, когда данные запрашиваются и данные обновляются. Лицо Framework сохраняет изменения объекта в база данных без проверки на параллелизм. Для субъектов, которые могут испытывать высокую степень параллелизма, мы рекомендуем сущность определяет свойство в концептуальный слой с атрибутом ConcurrencyMode = "fixed", как показано в следующий пример:

Любые конфликтующие изменения приведут к OptimisticConcurrencyException .

Для получения дополнительной информации см. Как: управлять параллелизмом данных в контексте объекта .

Короче говоря, измените ConcurrencyMode на Fixed и поймайте исключение OptimisticConcurrencyException ...

0 голосов
/ 31 июля 2016

Я знаю, что очень опоздал к этому, но с этим сталкиваются многие разработчики при разработке многопоточных приложений с использованием Entity Framework и wpf.Теперь вот пара вещей, на которые вы должны обратить внимание:

  1. ) вы не можете получить доступ к потоку пользовательского интерфейса из фонового потока.
  2. ) Dbcontext не является потокобезопасным, поэтому его использование вМногопоточная среда может вызвать проблемы, если не позаботиться

Итак, вот способ, которым я решил эту проблему. Мое решение следует абстрактному шаблону хранилища.Классы участия и интерфейсы:

  1. DataRepository и IDataRepository

  2. Student и IStudent

  3. StudentViewModel

  4. EntityBase

Это 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;
        }

Это 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);
       }
   }

thisтакое репозиторий студентов и 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); });
        }
    }

Тогда, наконец, Ваша точка зрения Модель

[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;}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...