Что такое DataService Лучшая практика с использованием Entity Framework и Repository Patterns и UnitOfWork
Я использую EF и MVVM шаблон. Мой вопрос касается уровня доступа к данным. в DAL у меня есть следующие классы:
MyObjectContext
который сейчас технически является стандартным ObjectContext, но некоторые методы Unit-of-Work будут добавлены к нему позже.Repository<TModel>
который обрабатывает наиболее необходимые запросы (такие как Add, GetAll, ...) в различных объектных наборах.Куча
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. Ниже хорошее видео на асинхронном.