1.) Я создаю новое MVC-приложение с 3-уровневой архитектурой проекта, имеющее:
- Общий проект с сущностями
- Интерфейсы для хранения бизнес-услуг и логические классы и
- Хранилища данных, интерфейсы,
DbContext
и UnitOfWork
классы.Я использую Unity Config для регистрации зависимостей DbContext
и UnitOfWork
.
2.) Я создал репозиторий для каждой таблицы и один общий репозиторий, который выполняет основные операции CRUD.
Пример сущности, находящейся в общем проекте:
public class MenuSecd
{
[Key, Column(Order = 0)]
public string prg_module { get; set; }
[Key, Column(Order = 1)]
public int prg_numb { get; set; }
[Key, Column(Order = 2)]
public string menu_level { get; set; }
}
Мой универсальный интерфейс логики сущности, находящийся в бизнес-проекте:
public interface IEntityLogic<T> : ILogic where T : class
{
void Create(T entity);
void Delete(T entity);
IEnumerable<T> GetAll();
void Update(T entity);
}
Класс логики сущности:
public abstract class EntityLogic<T> : IEntityLogic<T> where T : class
{
IUnitOfWork _unitOfWork;
IGenericRepository<T> _repository;
public EntityLogic(IUnitOfWork unitOfWork, IGenericRepository<T> repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_unitOfWork.Commit();
}
}
Пример класса бизнес-логики для сущности, определенной в общем проекте:
public class MenuSecdLogic : EntityLogic<MenuSecd>, IMenuSecdLogic
{
IUnitOfWork _unitOfWork;
IMenuSecdRepository _repository;
public MenuSecdLogic(IUnitOfWork unitOfWork, IMenuSecdRepository repository) : base(unitOfWork, repository)
{
_unitOfWork = unitOfWork;
_repository = repository;
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _repository.GetItems(usrgrp_id);
}
}
Мой общий репозиторий в проекте данных выглядит следующим образом:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
{
protected DbContext _entities;
protected readonly IDbSet<T> _dbset;
public GenericRepository(DbContext context)
{
_entities = context;
_dbset = context.Set<T>();
}
public virtual T Add(T entity)
{
return _dbset.Add(entity);
}
public virtual T Delete(T entity)
{
return _dbset.Remove(entity);
}
public virtual void Edit(T entity)
{
_entities.Entry(entity).State = EntityState.Modified;
}
}
Интерфейс репозитория для той же сущности определяется как:
public interface IMenuSecdRepository : IGenericRepository<MenuSecd>
{
List<MenuSecd> GetItems(string usrgrp_id);
}
Класс репозитория для вышеупомянутого интерфейса:
public class MenuSecdRepository : GenericRepository<MenuSecd>, IMenuSecdRepository
{
public MenuSecdRepository(DbContext context) : base(context)
{
}
public List<MenuSecd> GetItems(string usrgrp_id)
{
return _dbset.Where(m => m.usrgrp_id == usrgrp_id).ToList();
}
}
My DbContext
выглядит следующим образом:
public class DashboardContext : DbContext
{
public DashboardContext() : base("Name=DBEntities")
{
}
public DbSet<MenuSecd> menusecd { get; set; }
public override int SaveChanges()
{
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
//future custom implementation like auditing
return base.SaveChanges();
}
}
Мой UnitOfWork выглядит следующим образом:
public sealed class UnitOfWork : IUnitOfWork
{
private DbContext _dbContext;
public UnitOfWork(DbContext context)
{
_dbContext = context;
}
public int Commit()
{
return _dbContext.SaveChanges();
}
//disposes current object
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//disposes all external resources
private void Dispose(bool disposing)
{
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
_dbContext = null;
}
}
}
}
Мой контроллер:
public class DashController : Controller
{
private readonly IMenuSecdLogic _menuSecdLogic;
public DashController(IMenuSecdLogic menuSecdLogic)
{
_menuSecdLogic = menuSecdLogic;
}
public void Save()
{
var menuSecd = new menuSecd();
//populate all fields for entity MenuSecd
_menuSecdLogic.Create(menuSecd);
}
}
My Unity Config в App_Start выглядит следующим образом:
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<DbContext, DashboardContext>();
container.RegisterType<IUnitOfWork, UnitOfWork>();
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
container.RegisterType<IMenuSecdLogic, MenuSecdLogic>();
container.RegisterType<IMenuSecdRepository, MenuSecdRepository>();
}
Так что при запуске над проектом все строится нормально.Но когда контроллер вызывает:
_menuSecdLogic.Create(menuSecd);
Он достигает Entity Logic и добавляет новую сущность в _repository по адресу:
_repository.Add(entity);
_unitOfWork.Commit();
Но когда он нажимает следующую строку, чтобы фактически сохранить его в базе данных, которая является:
return _dbContext.SaveChanges();
в файле UnitOfWork.cs.Он приходит к dashboardContext, где он, наконец, должен сохранить его в базе данных.Но он выполняет:
var modifiedEntries = ChangeTracker.Entries().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
return base.SaveChanges();
Но в базе данных ничего не меняется.Там не будет записи в базе данных.Чтобы протестировать, я добавил измененные записи, чтобы увидеть, находится ли он в контексте или нет.К тому времени, когда контроль достигает этой точки, я не вижу никаких измененных записей вообще.Но в EntityLogic.cs
он добавляет новую сущность к локальным сущностям в хранилище.Я не уверен, что здесь происходит с UnitOfWork.Я запустил SQL Profiler, чтобы увидеть, попадает ли он в базу данных или нет.Интересно, что это не бьет по базе данных вообще.Но если я внесу следующие изменения в EntityLogic следующим образом:
public virtual void Create(T entity)
{
if(entity == null)
{
throw new ArgumentNullException(nameof(entity));
}
_repository.Add(entity);
_repository.Save();
//_unitOfWork.Commit();
}
Он попадет в базу данных, и записи будут сохранены в порядке.Но я не понимаю, почему это не отслеживание изменений и не попадание в базу данных, если я использую _unitOfWork.Commit()
, что я хочу сделать.Пожалуйста, помогите.