.net中的存储库模式和inheritance

我对存储库设计模式很陌生,在尝试实现它时,我已经达到了死胡同,关于inheritance。

即使我开始朝着正确的方向前进,我也不确定。

所以基本上我将有一个抽象基类Product,例如id和imagePath,并且将有几个inheritance自此的产品。

namespace Common { public abstract class Product { public int Id { get; set; } public string ImgPath { get; set; } } public class Scale : Product { public int AdditionalProperty { get; set; } } } 

现在存储库如下:

 public class BaseRepository { protected TEstEntities1 _dataContext = new TEstEntities1(); public BaseRepository() { _dataContext = new TEstEntities1(); } } public interface IProductRepository { Common.Product Get(int id); void Add(Common.Product p); void Update(Common.Product p); List ListAll(); } public class ProductRepository : BaseRepository, IProductRepository { public Common.Product Get(int id) { throw new NotImplementedException(); } public void Add(Common.Product p) { throw new NotImplementedException(); } public void Update(Common.Product p) { throw new NotImplementedException(); } public List ListAll() { throw new NotImplementedException(); } } 

我的问题如下:我如何整合有关Scale的操作? 将添加(Common.Scale s)之类的东西添加到IProductRepository似乎是一个坏主意。 在Add(Common.Product p)中看到我尝试添加哪种类型的产品,然后转换为它,然后添加,这似乎是一个坏主意。

我想如果我要更彻底地描述这个问题,我想重复尽可能少的代码,以某种方式隔离产品库中的基本产品添加/删除代码,并以某种方式将例如Scale特定代码添加到另一个内部类或方法。

我的一个更彻底的方法就是这个:

 public interface IProductRepository where T : Common.Product { T Get(int id); void Add(T p); void Delete(T p); } public abstract class ProductRepository : BaseRepository { protected void Add(Common.Product p) { _dataContext.AddToProduct(new Product { Id = p.Id, Image = p.ImgPath }); _dataContext.AcceptAllChanges(); } protected void Delete(Common.Product p) { var c = _dataContext.Product.Where(x => x.Id == p.Id).FirstOrDefault(); _dataContext.DeleteObject(c); _dataContext.AcceptAllChanges(); } protected Product Get(int id) { return _dataContext.Product.Where(x => x.Id == id).FirstOrDefault(); } } public class CantarRepository : ProductRepository, IProductRepository { public void Add(Common.Scale p) { base.Add(p); _dataContext.Scale.AddObject (new Scale { ProductId = p.Id, AdditionalProperty = p.AdditionalProperty }); _dataContext.AcceptAllChanges(); } public void Delete(Common.Scale p) { var c = _dataContext.Scale.Where(x => x.ProductId == p.Id); _dataContext.DeleteObject(c); _dataContext.AcceptAllChanges(); base.Delete(p); } public new Common.Scale Get(int id) { var p = base.Get(id); return new Common.Scale { Id = p.Id, ImgPath = p.Image, AdditionalProperty = _dataContext.Scale.Where (c => c.ProductId == id).FirstOrDefault().AdditionalProperty }; } } 

不幸的是,这有一个原因。 如果我使用工厂模式返回IProductRepository并在其中使用IProductRepository进行实例化,由于协方差和逆变,这将无法工作,并且IProductRepository不能同时具有逆变和协变性,并且将方法拆分为两个接口似乎违反直觉而且很麻烦。

我怀疑我需要工厂模式才能返回基类接口,但我也对这方面的建议持开放态度。 正如我所说,我对回购模式非常新手。

我很好奇我做错了什么,我怎么能解决这个问题,以及如何更好地实现这一点。

谢谢。

您正在使用inheritance错误。 如果重要的差异是附加属性,则不能将Scale视为(is-a)产品 – 这使得Scale的公开接口与Product不同,并且此时inheritance只会妨碍您。 使用inheritance来共享行为 ,而不是属性

使用inheritance试图解决什么问题?

我想重复尽可能少的代码

为了完成工作而不是一点点重复,而不是试图使用难以置信的设计?

此外,这是您与inheritance共享的所有内容:

  public int Id { get; set; } public string ImgPath { get; set; } 

重复两个自动实现的属性的定义几乎不具备重复的条件,它肯定不是一个值得关注的问题。

然而,滥用inheritance是相当严重的。 下一个维护你的应用程序的人会诅咒你。

所以基本上我将有一个抽象基类Product,例如id和imagePath,并且将有几个inheritance自此的产品。

那么当您添加新类型的产品时,您将不得不扩展inheritance层次结构? 这似乎是一个坏主意。

我不是通用存储库的忠实粉丝,但看了你的代码后我认为你应该使用它:

 public interface IEntity { int Id { get; } } public interface IRepository where T : class, IEntity { IQueryable GetQuery(); T Get(int id); void Add(T entity); void Update(T entity); void Delete(T entity); } 

执行:

 public Repository where T : class, IEntity { private ObjectSet _set; // or DbSet private ObjectContext _context; // or DbContext public Repository(ObjectContext context) // or DbContext { _context = context; _set = context.CreateObjectSet(); // _context.Set() for DbContext } public IQueryable GetQuery() { return _set; } public T Get(int id) { return _set.SingleOrDefault(e => e.Id == id); } public void Add (T entity) { _set.AddObject(entity); } public void Update(T entity) { _set.Attach(entity); context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified); // or context.Entry(entity).State = EntityState.Modified; for DbContext } public void Delete(entity) { _set.Attach(entity); _set.DeleteObject(entity); } } 

没有AcceptAllChanges因为它将重置ObjectStateManager并且永远不会保存您的更改。 没有物体的重建,因为它没有意义。

使用此存储库非常简单:

 var repo = new BaseRepository(context); repo.Add(new Product() { ... }); repo.Add(new Scale() { ... }); // yes this works because derived entities are handled by the same set context.Save(); 

我最近实现了这样的事情。 (使用您的样本类型名称)我有一个ProductRepository ,它知道如何持久化/取消所有Product子类型。

最终,您的后备数据存储必须能够存储各种子类型以及它们引入的任何属性。 您的存储库类型还必须知道如何利用每个给定子类型的这些function。 因此,每次添加子类型时,都会涉及到工作,例如,将表列添加到后备数据存储中以保存它可能引入的属性。 这意味着您还需要对存储库类型进行适当的更改。 因此,最简单的方法是在传递给您的存储库类型时检查实体的类型,如果它不是受支持的类型则抛出exception,因为您的存储库无法使用它。 类似地,在检索实体列表时,存储库必须知道如何检索每个实体子类型并构造实例。 由于这些都来自Product ,因此它们都可以在IEnumerable返回值中形成项目。