继承的通用存储库问题

Generic repository issue with inheritance

我在 .Net 中有 N 层解决方案,使用 PetaPoco 作为 microORM。我得到了从 PetaPoco 的模板生成器生成的实体。这些实体 T 来自基础 class Record<T>。然后我扩展它们,添加更多数据访问工具和自定义 Save()Delete() 方法来覆盖 Record<T> 默认方法。

以下是实体中覆盖的 Delete 方法(我要调用的方法)

public partial class Document : Record<Document>
{
    public new int Delete()
    {
        int rowsAffected;
        using (var uow = DB.GetInstance().GetTransaction())
        {
            rowsAffected = base.Delete();
            LogSystem("Deleting", "Deleting a document", 0, 0, GUID);
            uow.Complete();
        }
        return rowsAffected;
    }
}

然后,当我创建通用存储库时,调用的方法来自基础 class Record<T>,而不是来自实体的自定义方法。当我调用 entityRepository.Delete() 方法时,应该调用实体中的 Delete() 方法,而不是默认 Record<T> class.

中的方法

通用存储库 class 如下所示:

public abstract class GenericRepository<T> : IGenericRepository<T> where T : Record<T>, new()
{
    public void Delete(T entity)
    {
        entity.Delete();
    }
}

Confession: I have no knowledge of PetaPoco and its template generator.

与 PetaPoco 恕我直言相比,该问题与 OO(特别是继承)的相关性更高。如果通用存储库是使用 Record<T> 创建的,它也是每个实体的基础 class,那么发生的事情是预期的。您需要仔细研究 classes 的继承。

您可能需要对我在下面提出的解决方案进行一些更改以匹配 ORM 功能。

解决方案 1:

声明一个新的基础 class 或如下所示的接口:

public interface IEntityBase{.....

在接口中包含必要的成员,例如 Delete 方法。

然后,也从该接口派生每个实体:

public partial class Document : Record<Document>, IEntityBase

然后,使用此接口而不是 Record<T> something 创建一个通用存储库,如下所示:

public abstract class GenericRepository<T> : IGenericRepository<T> where T : IEntityBase

通过这种方式,您可以在不更改大部分现有代码的情况下实现 objective。

解决方案 2:

另一个解决方案是将Record<T>转换为它的实际实例。

public void Delete(T entity)
{
    if(typeof(T) == typeof(Document))
        Document myEntity = (Document)entity;
    myEntity.Delete();
}

在每个方法中进行强制转换绝对不是个好主意。在您的代码中寻找一些更好的集中位置。我只是想给你指路。

解决方案 3:

另一个想法是将 Record<T> 中的 Delete 方法变成 virtual 方法。但我不确定你的 ORM 是如何工作的,甚至你的 ORM 是否允许这样做,所以我不会对此发表评论。

这个问题的原因是在你的 GenericRepository 中你将 T 指定为 "something deriving from Record"。所以我们调用 entity.Delete(),这个调用将链接到这个基本方法,因为这只对 T 的所有可能实例执行一次。

如果您有权访问 Record<T> class,只需将 Delete() 方法设为虚拟方法并在 Document 中覆盖它。

如果没有,请尝试使用这样的方法:

public class ExtendedRecord<T>: Record<T>
{
  public virtual new int Delete()
  {
    base.Delete();
  }
}

public partial class Document : ExtendedRecord<Document>
{
  public override int Delete()
  {
    // ...
  }
}

public abstract class GenericRepository<T> : IGenericRepository<T>
  where T : ExtendedRecord<T>, new()
{
  // ...
}