使用 DBSet<>创建循环引用

本文关键字:循环 引用 创建 DBSet 使用 | 更新日期: 2023-09-27 18:36:37

我似乎无法弄清楚如何使用实体框架引用另一个dll(在同一解决方案中)中的类

错误 1 找不到类型或命名空间名称"Animal"(是否缺少 using 指令或程序集引用?

如果我尝试添加引用,我将创建一个循环引用。

public class AnimalDBContext : DbContext
{
    public AnimalDBContext()
        : base()
    {
    }
    public DbSet<Animal> Animals { get; set; }
}

这是对我来说似乎更正确的版本。但未必呢?

public class AnimalDBContext<TEntity> where TEntity  : DbContext
{
    public AnimalDBContext()
        : base()
    {
    }
    public DbSet<TEntity> Animals { get; set; }
}

这会导致以下编译器错误。

 AnimalDBContext < Animal > animal = new AnimalDBContext<Animal>();
Error   3   The type 'AnimalLibrary.Animals.Animal' cannot be used as type
parameter 'TEntity' in the generic type or method
ObjectSaver.AnimalDBContext<TEntity>'. There is no implicit reference conversion from
AnimalLibrary.Animals.Animal' to 'System.Data.Entity.DbContext'.    

使用 DBSet<>创建循环引用

因此,如果我理解正确,您的"存储库"程序集引用您的"域"程序集,这是有意义的,而您的"域"程序集引用您的"存储库"程序集,而"存储库"程序集则不然。

出于以下几个原因,实体类不应引用用于创建它们的存储库:

  • 正如您所发现的那样,它创建了一个循环依赖关系
  • 这使得模拟单元测试类变得更加困难
  • 您的实体绑定到一种类型的提供程序,因此将来很难更改提供程序

将存储库上的依赖项从域移动到单独的程序集中。

根据您的评论,听起来您至少需要三个组件 -

  • A) 数据访问,
  • B) 业务逻辑,以及
  • C) 域类。

理想情况下,A 和 B 应该引用 C,而不是彼此引用(反之亦然)。 您的域类不需要知道如何持久化自己 - 这是其他人的责任。

您可以从 A 引用 B,但这会阻止您"模拟"存储库来测试业务逻辑。 将数据访问和业务逻辑绑定到主应用程序引用的"服务"层中。 同样,您可以将服务和应用程序层捆绑在一起,但这也会增加耦合并降低可测试性。