EF Core、DI、存储库模式和基本存储库结构问题

EF Core, DI, Repository pattern and issue with base repository structure

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

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

因此,考虑一个实体。比方说 Product 下面是该实体的定义。此实体有一个名为 FullAuditedEntity 的基础 class。

[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;
    }
}

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

Issue I am facing : So with this structure, If I tries to add any new entity without FullAuditedEntity (see Product entity above, I have base class full audited entity over there), my structure of repository fails and it gives error.

假设我尝试添加新实体实现,而这个新实体有一个随机 ID,所以我不想继承 FullAuditedEnitity 基础 class .现在在这种情况下,大部分事情都可以正常工作,但是当我尝试为实现实体创建存储库时,它会给出一般错误。请看下面的截图。

What I tried so far...

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

任何帮助世界变得最好的人,我们都非常感激。

提前感谢您的宝贵时间。

存储库通常映射到数据库 table。数据库 table 应该总是有一些列可以唯一标识 table 中的行,通常的做法是将此列称为 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 的行 table.

更新:

如果不想继承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:

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

  1. 对Repository

  2. 获取的数据添加一些计算
  3. 重新映射存储库拉取的实体

  4. 又多了一层解耦。所以当你编辑你的服务层时,你不需要编辑存储层然后重新编译你的程序集