gpt4 book ai didi

c# - MVC5 + EF + UOW + 服务层在哪里调用 SaveChanges() 并避免多次访问 DB?

转载 作者:太空狗 更新时间:2023-10-29 23:51:04 27 4
gpt4 key购买 nike

我正在使用 MVC5EF Code First 以及 RepositoryUnit of Work 构建网络应用程序> 图案。到目前为止,我有 3 层:

  • 包含存储库 UOW 的“数据层”。
  • 引用 UOW 的“服务层”来实现业务逻辑和业务验证。
  • “Web 层”负责通过与服务层通信来显示数据。

我的域/业务对象在另一个项目中是分开的。所以基本上我在关注 John Papa CodeCamper除了添加“服务层”之外的结构。

Data/Contracts/IRepository.cs

public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
void Delete(int id);
}

数据/契约(Contract)/IUnitOfWork.cs

public interface IUnitOfWork
{
// Save pending changes to the data store.
void Commit();

// Repositories
IRepository<Event> Events { get; }
IRepository<Candidate> Candidates { get; }
}

数据/EFRepository.cs

/// <summary>
/// The EF-dependent, generic repository for data access
/// </summary>
/// <typeparam name="T">Type of entity for this Repository.</typeparam>
public class EFRepository<T> : IRepository<T> where T : class
{
public EFRepository(DbContext dbContext)
{
if (dbContext == null)
throw new ArgumentNullException("dbContext");
DbContext = dbContext;
DbSet = DbContext.Set<T>();
}

protected DbContext DbContext { get; set; }

protected DbSet<T> DbSet { get; set; }

public virtual IQueryable<T> GetAll()
{
return DbSet;
}

public virtual T GetById(int id)
{
//return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
return DbSet.Find(id);
}

public virtual void Add(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
}

public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
DbSet.Attach(entity);
}
dbEntityEntry.State = EntityState.Modified;
}

public virtual void Delete(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Deleted)
{
dbEntityEntry.State = EntityState.Deleted;
}
else
{
DbSet.Attach(entity);
DbSet.Remove(entity);
}
}

public virtual void Delete(int id)
{
var entity = GetById(id);
if (entity == null) return; // not found; assume already deleted.
Delete(entity);
}
}

数据/UnitOfWork.cs

/// <summary>
/// The "Unit of Work"
/// 1) decouples the repos from the controllers
/// 2) decouples the DbContext and EF from the controllers
/// 3) manages the UoW
/// </summary>
/// <remarks>
/// This class implements the "Unit of Work" pattern in which
/// the "UoW" serves as a facade for querying and saving to the database.
/// Querying is delegated to "repositories".
/// Each repository serves as a container dedicated to a particular
/// root entity type such as a <see cref="Url"/>.
/// A repository typically exposes "Get" methods for querying and
/// will offer add, update, and delete methods if those features are supported.
/// The repositories rely on their parent UoW to provide the interface to the
/// data layer (which is the EF DbContext in this example).
/// </remarks>
public class UnitOfWork : IUnitOfWork, IDisposable
{
public UnitOfWork(IRepositoryProvider repositoryProvider)
{
CreateDbContext();

repositoryProvider.DbContext = DbContext;
RepositoryProvider = repositoryProvider;
}

// Repositories
public IRepository<Student> Students { get { return GetStandardRepo<Event>(); } }
public IRepository<Course> Courses { get { return GetStandardRepo<Course>(); } }

/// <summary>
/// Save pending changes to the database
/// </summary>
public void Commit()
{
//System.Diagnostics.Debug.WriteLine("Committed");
DbContext.SaveChanges();
}

protected void CreateDbContext()
{
DbContext = new UnicornsContext();

// Do NOT enable proxied entities, else serialization fails
DbContext.Configuration.ProxyCreationEnabled = false;

// Load navigation properties explicitly (avoid serialization trouble)
DbContext.Configuration.LazyLoadingEnabled = false;

// Because Web API will perform validation, I don't need/want EF to do so
DbContext.Configuration.ValidateOnSaveEnabled = false;
}

protected IRepositoryProvider RepositoryProvider { get; set; }

private IRepository<T> GetStandardRepo<T>() where T : class
{
return RepositoryProvider.GetRepositoryForEntityType<T>();
}
private T GetRepo<T>() where T : class
{
return RepositoryProvider.GetRepository<T>();
}

private UnicornsContext DbContext { get; set; }

#region IDisposable

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (DbContext != null)
{
DbContext.Dispose();
}
}
}

#endregion
}

然后最后使用Ninject解决依赖:

kernel.Bind<RepositoryFactories>().To<RepositoryFactories>().InSingletonScope();
kernel.Bind<IRepositoryProvider>().To<RepositoryProvider>();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>();

我应该在哪里调用 UOW.Commit() 以便我可以在其他服务中重用特定服务的已实现逻辑而不是重新编写它?

  1. Controller 是否应该负责提交更改?
  2. 还是服务本身应该提交更改?

据我在 Stack Overflow 上读到的,option(1) 更简单但违反了单一职责原则或者如果我想与移动/桌面应用程序集成会出现什么情况。

选项(2):我在这里必须在每个服务函数调用中调用提交,因此我将无法重用函数因为这可能会导致多次访问 DB。

最佳答案

在我的项目中,我在 Controller 中调用 Save(),因为我想尽可能多地重用我的方法,而当它们自己调用 Save() 时,将多个方法“粘合”在一起是很困难的。更糟糕的是,如果在 Controller 级别存在错误,您可能希望避免调用 save(),例如一些方法创建了一堆小对象,这些对象用于必须提交的主对象。同时提交两者似乎比在 createSMallObject() 和 createMasterObject() 中硬编码提交要好,以防中间发生某些事情。

关于c# - MVC5 + EF + UOW + 服务层在哪里调用 SaveChanges() 并避免多次访问 DB?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24616316/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com