我已经找到了一个可行的解决方案(使用DTO和AutoMapper),如下所示,但我更希望得到一份列出不同解决方法的答案,并给出示例。如果有这样的答案,我会将其标记为最佳答案。
我的实体模型中有从子实体到父实体的导航属性。我的项目一直运行良好。然后我开始使用AutoFixture进行单元测试,测试失败了,AutoFixture说我有一个循环引用。
现在,我意识到像这样的循环引用导航属性在Entity Framework中是可以的,但我发现了这篇文章(Use value of a parent property when creating a complex child in AutoFixture),其中AutoFixture的创建者Mark Seemann说:
“顺便说一句,我已经好几年没有编写具有循环引用的API了,因此完全可以避免那些父/子关系。”
所以,我想了解如何重构领域模型以避免子/父关系。
以下是相关的实体类、存储库方法以及我在View中使用导致循环引用���属性。 完美的答案将解释我可以选择的不同选项,并提供示例,以及每种方法的基本优缺点。
注意:导致循环引用的属性是UserTeam模型中的User。
Models:
public class UserProfile
{
public UserProfile()
{
UserTeams = new HashSet<UserTeam>();
Games = new HashSet<Game>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual ICollection<UserTeam> UserTeams { get; set; }
public virtual ICollection<Game> Games { get; set; }
}
public class Game
{
public Game()
{
UserTeams = new HashSet<UserTeam>();
}
public int Id { get; set; }
public int CreatorId { get; set; }
public virtual ICollection<UserTeam> UserTeams { get; set; }
}
public class UserTeam
{
public UserTeam()
{
UserTeam_Players = new HashSet<UserTeam_Player>();
}
public int Id { get; set; }
public int UserId { get; set; }
public int GameId { get; set; }
public virtual UserProfile User { get; set; }
public virtual ICollection<UserTeam_Player> UserTeam_Players { get; set; }
}
仓库模式
public IEnumerable<Game> GetAllGames()
{
using (DataContext)
{
var _games = DataContext.Games
.Include(x => x.UserTeams)
.Include(x => x.UserTeams.Select(y => y.User))
.ToList();
if (_games == null)
{
// log error
return null;
}
return _games;
}
}
查看
@model IEnumerable<Game>
@foreach (var item in Model){
foreach (var userteam in item.UserTeams){
<p>@userteam.User.UserName</p>
}
}
现在,如果我移除 'User' 导航属性,我将无法执行 '@userteam.User.UserName'。
那么,如何重构领域模型以删除循环引用,同时能够轻松地遍历游戏,并执行类似 UserTeam.User.Username 的操作?