EF Core,DI,存储库模式以及基本存储库结构问题

时间:2019-11-09 07:11:00

标签: c# dependency-injection repository-pattern asp.net-core-2.1 ef-core-2.1

我有.net core rest api,它包含混合结构,其中仅包含存储库,而不包含服务层。

现在,基本存储库和主结构面临一个问题。让我先解释一下这个问题。

因此,考虑一个实体。假设产品,下面是该实体的定义。该实体具有一个称为 FullAuditedEntity 的基类。

[Table(name: "Products")]
public class Product : FullAuditedEntity
{
    public string Name { get; set; }
}

public class FullAuditedEntity: IFullAuditedEntity
{
    public FullAuditedEntity() { }

    [Key]
    public virtual int Id { get; set; }
}

public interface IFullAuditedEntity
{
    int Id { get; set; }
}

基本存储库及其界面如下。

public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IFullAuditedEntity, new()
{
    private readonly ApplicationContext context;

    public EntityBaseRepository(ApplicationContext context)
    {
        this.context = context;
    }

    public virtual IEnumerable<T> items => context.Set<T>().AsEnumerable().OrderByDescending(m => m.Id);

    public virtual T GetSingle(int id) => context.Set<T>().FirstOrDefault(x => x.Id == id);
}

public interface IEntityBaseRepository<T> where T : class, new()
{
    IEnumerable<T> items { get; }
    T GetSingle(int id);
}

因此,我的产品存储库将是这样。

public interface IProductRepository : IEntityBaseRepository<Product> { }

public class ProductRepository : EntityBaseRepository<Product>, IProductRepository
{
    private readonly ApplicationContext context;

    public ProductRepository(ApplicationContext context) : base(context: context)
    {
        this.context = context;
    }
}

现在,到目前为止一切都很好,我可以在控制器中访问此存储库,并可以执行基类中列出的操作。

  

我面临的问题:因此,采用这种结构,如果我尝试添加没有FullAuditedEntity的任何新实体(请参见上面的产品实体,我在那里具有基类的完整审计实体),存储库失败,并显示错误。

如果我尝试添加新实体实施,并且该新实体具有随机ID,那么我不想继承FullAuditedEnitity基类。现在在这种情况下,大多数事情都可以正常工作,但是当我尝试为实现实体创建存储库时,它将给出一般错误。参见下面的快照。

enter image description here

  

到目前为止我尝试过的...

我当时正在考虑创建一个并行的Base存储库,该存储库不会继承FullAuditedEntity作为通用类,但是我不确定这是否是最佳实践。我还担心如果我在当前的存储库模式和依赖注入结构中犯任何错误怎么办?

任何帮助世界都是最好的,并且真的很感激。

提前感谢您的时间。

1 个答案:

答案 0 :(得分:2)

存储库通常映射到数据库表。数据库表应始终具有一些可以唯一标识表中行的列,通常的做法是将此列称为Id。因此,您可以正确实现FullAuditedEntity,因为它具有Id属性。但是,您的Id的类型始终为int。我建议您使用以下构造,然后您的Id将是任何类型的结构,例如intdecimalGuid等:

/// <summary>
/// Abstraction of the Entity
/// </summary>
public interface IEntity
{
    object Id { get; set; }        
}


/// <summary>
/// Base class for IDs
/// </summary>
public abstract class Entity<T>: IEntity where T: struct
{        
    public T Id { get; set; }

    object IEntity.Id
    {
        get { return Id; }
        set {                
            Id = (T)value;
        }
    }
}

public class EntityBaseRepository<T> : IEntityBaseRepository<T> where T : class, IEntity, new()
{ 
    // The code is omitted for the brevity
}

此外,尝试避免使用像Id这样没有Implementation的实体,因为将来您将不得不弄清楚如何在数据库表中查找没有Id的行。

更新:

如果您不想继承FullAuditedEntity,则可以创建BaseRepository<T>,然后在EntityBaseRepository中派生它。

public abstract class BaseRepository<T> : IEntityBaseRepository<T> where T : class, new()
{
    public virtual IEnumerable<T> items => throw new NotImplementedException();

    public virtual T GetSingle(int id)
    {            
        throw new NotImplementedException();
    }
}

public class EntityBaseRepository<T> : BaseRepository<T> where T : class
                                             , IFullAuditedEntity, new()
{
    public override IEnumerable<T> items => base.items;

    public override T GetSingle(int id)
    {
        return base.GetSingle(id);            
    }
}

,然后是您的Implementation存储库:

public interface IImplementationRepository : IEntityBaseRepository<Implementation> { }


public class ImplementationRepository: BaseRepository<Implementation>
    , IImplementationRepository
{
    public override Implementation GetSingle(int id)
    {

        return base.GetSingle(id);
    }
}

更新1:

在我看来,最好使用消耗Service layer的服务(ITRepository<T>)。 因为它为您提供了新的功能,例如:

  1. 对存储库获得的数据进行一些计算

  2. 重新映射由存储库拉出的实体

  3. 这是去耦的另一层。因此,当您编辑服务层时,无需编辑存储库层然后重新编译程序集