.net中的存储库模式和继承

Imm*_*bat 6 .net c# inheritance entity-framework repository-pattern

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

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

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

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在存储库如下:

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<Common.Product> 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<Common.Product> ListAll()
    {
        throw new NotImplementedException();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

public interface IProductRepository<T> 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<Common.Scale>
{
    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
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我怀疑我需要工厂模式才能返回基类接口,但我也愿意接受这方面的建议.正如我所说,我对回购模式非常新手.

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

谢谢.

Ada*_*lph 1

我最近实施了这样的事情。ProductRepository(使用您的示例类型名称)我有一个知道如何保留/取消保留所有子类型的单个Product

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