我在 EF Core Code First Approach 中使用 AutoFixture 遇到异常“AutoFixture.ObjectCreationExceptionWithPath”

问题描述

我目前正在使用 EF Core Code First Approach,并且我有以下域类:

public class Employee
{
  // several properties such as Name,Address,...

  public Guid? CompanyId { get; set; }

  public Company Company {get;set;}

}

 public class Company
{
   public Guid? CompanyId { get; set; }

   public IEnumerable<Employee>? Employee{ get; set; }
}

我正在使用 XUnit 和 Autofixture 创建我的测试:

public class MyTest{

 private readonly Fixture _fixture = new Fixture();

[Fact]
public void TestMethod(){

var employee =  _fixture.Create<Employee>();
...
}

}

上面的 _fixture.Create 给了我以下错误

  Message: 
    AutoFixture.ObjectCreationExceptionWithPath : AutoFixture was unable to create an instance of type AutoFixture.Kernel.FiniteSequenceRequest because the traversed object graph contains a circular reference.

我需要在 Employee 类中包含:public Company Company {get;set;} 以使其成为外键。但是如果我删除那条线,它就可以正常工作。

许多在线链接都提出了以下解决方案 - 但我想知道是否有另一种方法而不是删除 ThrowingRecursion 行为:

fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
    .ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());

解决方法

这可能不是您如何使用 AutoFixture 的问题的直接答案...有多种可能的选择:

  1. 您可以按照问题中的建议自定义 AF
  2. 您可以配置 EF Core 外键 without using navigation property
  3. 或者,您可以将代码设计更改为更具 DDD 风格。这可能会帮助您避免任何 AF 自定义,但也可能会更耗时...

使您的代码更加“DDD-ish”的第一步是关闭公共 setter 并开始通过构造函数或方法参数管理您的实体。这将使 AF 创建您的类而无需循环依赖。 EF Core 也足够智能,能够将值设置为受保护的成员。代码可能如下所示:

public class Employee
{
  // closed setter,no AF issues,EF Core will still work
  public Company Company {get; protected set;} 

  // Some functionality from your domain model
  public void JoinCompany(Company company)
  {
      // do smth here.
      Company = company
  }

  public void LeaveCompany()
  {
      Company = null;
  }
}

或者,从公司的角度来看,API 可能如下所示(同样,我不知道您的域模型,所以只是原型设计):

public class Company
{
    private List<Employee> _employee = new List<Employee>();

    public IReadOnlyCollection<Employee> Employee => _employee;

    public void EnrollEmployee(Employee employee)
    {
        _employee.Add(employee);
    }
}

可以在此处找到一些代码示例:https://github.com/vkhorikov/DddAndEFCore/blob/master/src/App/Student.cs