我一直在查看一些博客文章,尝试为以下要求创建一个合适的解决方案,但我似乎无法将它们拼凑在一起。希望完全有人可以提供帮助。
我一直在使用Repository模式和使用Automapper的接口...这是一个精简的例子:
public class BookingRepository : IBookingRepository
{
Entities context = new Entities();
public IEnumerable<BookingDto> GetBookings
{
get { return Mapper.Map<IQueryable<Booking>, IEnumerable<BookingDto>>(context.Bookings); }
}
public BookingDto GetBookingWithProduct(Guid bookingId)
{
return Mapper.Map<BookingDto>(context.Bookings.Include(c => c.Products).SingleOrDefault(c => c.BookingId == bookingId));
}
public void Update(BookingDto bookingDto)
{
var booking = Mapper.Map<Booking>(bookingDto);
context.Entry(booking).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IBookingRepository : IDisposable
{
IEnumerable<BookingDto> GetBookings { get; }
BookingDto GetBooking(Guid bookingId);
void Update(BookingDto bookingDto);
void Save();
}
为不同的实体提供单独的存储库,例如
public class ProductRepository : IProductRepository
{
Entities context = new Entities();
public IEnumerable<ProductDto> GetProducts
{
get { return Mapper.Map<IQueryable<Product>, IEnumerable<ProductDto>>(context.Products); }
}
public ProductDto GetProductWithDesign(int productId)
{
return Mapper.Map<ProductDto>(context.Products.Include(c => c.Designs).SingleOrDefault(c => c.ProductId == productId));
}
public void Update(ProductDto productDto)
{
var product = Mapper.Map<Product>(productDto);
context.Entry(product).State = EntityState.Modified;
}
public void Save()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
public interface IProductRepository : IDisposable
{
IEnumerable<ProductDto> GetProducts { get; }
ProductDto GetProduct(int productId);
void Update(ProductDto productDto);
void Save();
}
然后在我的Controller中,我正在使用存储库:
public class HomeController : Controller
{
private readonly IBookingRepository bookingRepository;
private readonly IProductRepository productRepository;
public HomeController() : this(new BookingRepository(), new ProductRepository()) { }
public HomeController(IBookingRepository bookingRepository, IProductRepository productRepository)
{
this.bookingRepository = bookingRepository;
this.productRepository = productRepository;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && this.bookingRepository != null)
this.bookingRepository.Dispose();
if (disposing && this.productRepository != null)
this.productRepository.Dispose();
}
}
所以现在我希望创建一个工作单元来抽象这些存储库并共享上下文,并为重复的操作(保存和更新)创建一个通用存储库,同时记住我正在传递Dtos和映射到实体对象。我很难理解如何将它们编织在一起。
另外,我看过这篇文章
Repository pattern with generics and DI
指出“除了你的通用存储库之外你不应该有其他存储库接口”,并且自定义查询“应该得到他们自己的(通用)抽象:”这会给我过度工作的大脑增加另一个复杂因素,因为我的存储库将有自定义查询返回使用“包含语句作为延迟加载”的复杂链接对象已禁用。
所以我准备被击落并告诉我这是错误的做法,但对任何指示都会感激不尽。
提前致谢。
答案 0 :(得分:5)
不要使用通用存储库。它们都是漏洞抽象。问问自己,使用抽象并没有真正抽象出来的东西会给你带来什么好处?在这些情况下,您可以直接使用OR / M.
我的意思是任何暴露IQueryable<T>
的东西都会迫使用户了解潜在的OR / M所具有的弱点。示例:orm如何处理延迟加载?我如何热切地加载相关实体?如何创建IN
子句?
如果您确实想要使用存储库模式,请将其与规范模式一起使用(您可以继续使用通用存储库)或创建特定于每个根聚合的存储库。
我在博客上写过:http://blog.gauffin.org/2013/01/repository-pattern-done-right/
答案 1 :(得分:0)
在这种情况下我通常做的是创建一个这样的Base抽象存储库类:
public abstract class BaseRepository<T> : IRepository<T>
{
Entities context = new Entities();
public virtual T GetAll()
{
return context.Set<T>();
}
// Add base implementation for normal CRUD here
}
如果您不需要特殊查询,则无需创建特殊的界面和类(但当然,您可以提高可读性)。所以你将使用,例如:
var bookingsRepo = new BaseRepository<BookingsDto>();
var allBookings = bookingsRepo.GetAll();
如果您需要一些特殊查询,可以创建一个扩展基接口的接口:
public interface IProductRepository : IRepository<Product>
{
Product GetSpecialOffer();
}
然后创建你的课程:
public class ProductRepository : BaseRepository<Product>, IProductRepository
{
public Product GetSpecialOffer()
{
// your logic here
}
}
这样,您只需指定最少数量的特殊情况,同时依赖Base抽象实现来处理所有正常情况。
我将virtual
添加到基本方法中,因为我总是希望派生类能够覆盖内容......