Что такое DataService Лучшая практика с использованием Entity Framework и Repository Patterns и UnitOfWork

Я использую EF и MVVM шаблон. Мой вопрос касается уровня доступа к данным. в DAL у меня есть следующие классы:

  1. MyObjectContext который сейчас технически является стандартным ObjectContext, но некоторые методы Unit-of-Work будут добавлены к нему позже.

  2. Repository<TModel> который обрабатывает наиболее необходимые запросы (такие как Add, GetAll, ...) в различных объектных наборах.

  3. Куча DataServices которые используют репозитории для обеспечения более высокого уровня доступа к данным для Core.

Проект, над которым я работаю, на данный момент является бизнес-приложением с около 100 EntitySets, и бывают случаи, когда одно взаимодействие пользователя может включать до 20 различных EntitySets (обновление большинства из них). Я в настоящее время добавляю .Include(params string[]) на мои запросы, чтобы предотвратить ObjectContextDisposedException но это не кажется надежным решением.

Вопрос в том, должен ли я создать экземпляр MyObjectContext (и, следовательно, репозиторий) в каждом из методов DataService (например, в следующих кодах, мне кажется, что в этом случае способность единицы работы будет бесполезна) или я должен создать ее вне DataService и передать ее в DataServices через их конструкторы (или непосредственно к каждому из методов DataService) для совместной обработки нескольких действий базы данных (разных таблиц и запросов). И как?

Вот что MyObjectContext похоже:

public class MyObjectContext : ObjectContext, IUnitOfWork
{
    public MyObjectContext()
        : base("name=EdmContainer", "EdmContainer")
    {
        ContextOptions.LazyLoadingEnabled = true;
    }

    #region IUnitOfWork Members
    public void Commit()
    {
        SaveChanges();
    }
    #endregion
}

Вот как Repository похоже:

public class Repository<TModel>
{
    private readonly SoheilEdmContext _context;

    public Repository(IUnitOfWork unitOfWork)
    {
        if (unitOfWork == null)
            throw new ArgumentNullException("unitOfWork");

        _context = unitOfWork as SoheilEdmContext;
    }
    public TModel FirstOrDefault(Expression<Func<TModel, bool>> where)
    {
        return _context.CreateObjectSet<TModel>().FirstOrDefault(where);
    }
    public void Add(TModel entity)
    {
        _context.CreateObjectSet<TModel>().AddObject(entity);
    }
    ...
}

И это как общее DataService похоже:

public class JobDataService : IDataService<Job>
{
    #region IDataService<Job> Members
    public Job GetSingle(int id)
    {
        Job model = null;
        using (var context = new MyObjectContext())
        {
            var repos = new Repository<Job>(context);
            model = repos.FirstOrDefault(x => x.Id == id);
        }
        return model;
    }

    public IEnumerable<Job> GetAll()
    {
        using (var context = new MyObjectContext())
        {
            var repos = new Repository<Job>(context);
            var models = repos.GetAll();
            return models;
        }
    }

    public IEnumerable<Job> GetActives()
    {
        throw new NotImplementedException();
    }

    public int AddModel(Job model)
    {
        using (var context = new MyObjectContext())
        {
            var repos = new Repository<Job>(context);
            repos.Add(model);
            context.SaveChanges();
        }
    }

    public void UpdateModel(Job model)
    {
        throw new NotImplementedException();
    }

    public void DeleteModel(Job model)
    {
        using (var context = new MyObjectContext())
        {
            var repos = new Repository<Job>(context);
            var model = repos.FirstOrDefault(x => x.Id == model.Id);
            if (model == null) return;
            repos.Delete(model);
            context.SaveChanges();
        }
    }
    #endregion
}

Любая идея или понимание будут оценены.

1 ответ

Решение

Вы можете создать экземпляр MyObjectContext в каждой службе, например, JobDataService, однако это усложняет ваш код и его трудно поддерживать. Лучше создать экземпляр MyObjectContext вне DataService. Что у вас есть сейчас, если у вас есть 100 EntitySets, вам нужно создать 100 DataServices. Это связано с тем, что использование "Repository Pattern" и "UnitOfWork" здесь неэффективно. Я бы предложил сделать следующее:

ObjectContext

public class MyObjectContext : ObjectContext
{
    public MyObjectContext() : base("name=EdmContainer", "EdmContainer")
    {
        ContextOptions.LazyLoadingEnabled = true;
    }

    #region IUnitOfWork Members
    public void Commit()
    {
        SaveChanges();
    }
    #endregion
}

Универсальный репозиторий

 public interface IRepository<TModel> where TModel : class
    {
        void Add(TModel entity);
        IEnumerable<TModel> GetAll();
        // Do some more implement
    }


    public class Repository<TModel> : IRepository<TModel> where TModel : class
    {
        private readonly ObjectContext _context;

        public Repository(ObjectContext context)
        {
            _context = context;
        }

        public virtual void Add(TModel entity)
        {
            _context.CreateObjectSet<TModel>().AddObject(entity);
        }

        public virtual IEnumerable<TModel> GetAll()
        {
            return _context.CreateObjectSet<TModel>();
        }
    }

UnitOfWork

public interface IUnitOfWork : IDisposable
{
    IRepository<Job> Jobs { get; }
    IRepository<User> Users { get;} 
    void Commit();
}

    public class UnitOfWork : IUnitOfWork
    {
        private readonly SoheilEdmContext _context;
        private readonly IRepository<Job> _jobRepository;
        private readonly IRepository<User> _userRepository; 

        public UnitOfWork(SoheilEdmContext context)
        {
            _context = context;
            _jobRepository = new Repository<Job>(_context);
            _userRepository = new Repository<User>(_context);
        }
        public IRepository<Job> Jobs{get { return _jobRepository; }}
        public IRepository<User> Users{get { return _userRepository; }}
        public void Commit(){_context.Commit();}
        public void Dispose()
        {
            if (_context != null)
            {
                _context.Dispose();
            }

            GC.SuppressFinalize(this);
        }

JodDataSerivce

public interface IDataService
        {
            IEnumerable<Job> GetAll();
        }

        public class DataService : IDataService
        {
            private readonly IUnitOfWork _unitOfWork;
            public DataService(IUnitOfWork unitOfWork)
            {
                _unitOfWork = unitOfWork;
            }

            public IEnumerable<Job> GetAll()
            {
                return _unitOfWork.Jobs.GetAll();
            }
        }

Здесь я использовал интерфейс для реализации всего, если вы хотите сделать то же самое, вам нужно использовать IoC Container. Я использовал "Простой Инжектор", вы можете найти его здесь:

Простой инжектор

Еще одно предложение: если вы чувствуете, что у вас слишком много операций ввода-вывода для реализации, таких как доступ к базе данных, запрос данных и т. Д., Вам следует рассмотреть возможность использования Asynchronous. Ниже хорошее видео на асинхронном.

Как создавать веб-приложения ASP.NET с помощью Async

Другие вопросы по тегам