【发布时间】:2016-10-06 22:18:27
【问题描述】:
我尝试在我的应用程序中使用存储库设计模式有两个原因
我喜欢将我的应用程序与 Entity 分离,以防我决定在某些时候不使用 Entity Framework
我希望能够重用与模型交互的逻辑
我成功设置并使用了存储库模式。但是,我需要处理一个复杂的事务。
我希望能够使用事务,以便我可以多次调用存储库,然后提交或回滚。
这是我的仓库界面
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Support.Repositories.Contracts
{
public interface IRepository<TModel> where TModel : class
{
// Get records by it's primary key
TModel Get(int id);
// Get all records
IEnumerable<TModel> GetAll();
// Get all records matching a lambda expression
IEnumerable<TModel> Find(Expression<Func<TModel, bool>> predicate);
// Get the a single matching record or null
TModel SingleOrDefault(Expression<Func<TModel, bool>> predicate);
// Add single record
void Add(TModel entity);
// Add multiple records
void AddRange(IEnumerable<TModel> entities);
// Remove records
void Remove(TModel entity);
// remove multiple records
void RemoveRange(IEnumerable<TModel> entities);
}
}
然后我像这样为实体框架创建一个实现
using Support.Repositories.Contracts;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace Support.Repositories
{
public class EntityRepository<TEntity> : IRepository<TEntity>
where TEntity : class
{
protected readonly DbContext Context;
protected readonly DbSet<TEntity> DbSet;
public EntityRepository(DbContext context)
{
Context = context;
DbSet = context.Set<TEntity>();
}
public TEntity Get(int id)
{
return DbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return DbSet.ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.SingleOrDefault(predicate);
}
public void Add(TEntity entity)
{
DbSet.Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
DbSet.AddRange(entities);
}
public void Remove(TEntity entity)
{
DbSet.Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
DbSet.RemoveRange(entities);
}
}
}
现在,我创建了一个 IUnitOfWork 来像这样与存储库进行交互
using System;
namespace App.Repositories.Contracts
{
public interface IUnitOfWork : IDisposable
{
IUserRepository Users { get; }
IAddressRepository Addresses { get; }
}
}
然后我为实体框架实现了这个接口,如下所示:
using App.Contexts;
using App.Repositories.Contracts;
using App.Repositories.Entity;
namespace App.Repositories
{
public class UnitOfWork : IUnitOfWork
{
private readonly AppContext _context;
public IUserRepository Users { get; private set; }
public IAddressRepository Addresses { get; private set; }
public UnitOfWork(AppContext context)
{
_context = context;
Users = new UserRepository(_context);
Addresses = new AddressRepository(_context);
}
public UnitOfWork() : this(new AppContext())
{
}
public int Save()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
}
我可以像这样使用存储库
using(var repository = new UnitOfWork())
{
repository.Users.Add(new User(... User One ...))
repository.Save();
repository.Addresses(new Address(... Address For User One ...))
repository.Save();
repository.Users.Add(new User(... User Two...))
repository.Save();
repository.Addresses(new Address(... Address For User Two...))
repository.Save();
}
现在,我希望能够使用数据库事务,所以只有在一切正常时才提交,否则回滚。
我的第一个想法是在我的UnitOfWork 类中添加一个名为BeginTransaction() 的新方法。但只会将我的代码耦合到实体框架。
现在,我正在考虑创建一个提供BeginTransaction()、Commit() 和Rollback() 方法的新接口,这将允许我为任何ORM 编写实现。
即
namespace Support.Contracts
{
public IRepositoryDatabase
{
SomethingToReturn BeginTransaction();
void Commit();
void Rollback();
}
}
问题是我如何将IRepositoryDatabase 绑定到我的 UnitOfWork 以便我可以正确实施? BeginTransaction() 需要返回什么?
【问题讨论】:
-
EF 将默认存储所有更改的实体,或者在 Save() 调用时不存储。
-
但是我该如何开始交易呢?
-
更改 10 个实体,然后调用 Save()。它将由 EF 在单个事务中写入(如果发生任何错误,则不会写入任何内容)。
-
var user = new User(); var 地址 = 新地址 { 用户 = 用户 };
-
如果我想更改为不同的框架而不是实体怎么办。可能是其他框架不能像实体一样处理所有事情。我不需要某种包装器来确保无论实现如何都能正常工作吗?
标签: c# entity-framework transactions repository repository-pattern