问题描述
我目前正在使用 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 的问题的直接答案...有多种可能的选择:
- 您可以按照问题中的建议自定义 AF
- 您可以配置 EF Core 外键 without using navigation property
- 或者,您可以将代码设计更改为更具 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