从数据库获取结果时禁止循环引用

时间:2019-04-05 19:46:19

标签: c# recursion ef-core-2.2

如果我有以下简单模型:

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

        public ICollection<CompanyUser> Users { get; set; }
    }

    public class CompanyUser
    {
        public Guid CompanyId { get; set; }

        public Guid UserId { get; set; }

        public Company Company { get; set; }

        public User User { get; set; }
    }

    public class User
    {
        public Guid UserId { get; set; }

        public ICollection<CompanyUser> Companies { get; set; }
    }

要获取公司及其用户+用户对象的列表,请运行以下查询:

return await _dataContext.Companies
    .Include(m => m.Users)
    .ThenInclude(m => m.User)
    .OrderBy(m => m.Name)
    .ToListAsync();

结果有效,但我使用映射器通过逐个遍历模型将结果映射到视图模型。

发生的事情是Company对象引用了CompanyUser的列表,在每个CompanyUser对象中,我们都有一个Company,其中包含一个{再次CompanyUser,只是不断重复直到出现堆栈溢出。

enter image description here

映射器是一个非常简单的映射器:

var results = companies.ToViewModel<Company, CompanyViewModel>();
public static IList<TModel> ToViewModel<TEntity, TModel>(this IEnumerable<TEntity> entities)
    where TEntity : class
    where TModel : class, IViewModel<TEntity>, new()
{
    return entities?.Select(entity => entity.ToViewModel<TEntity, TModel>()).ToList();
}

public static TModel ToViewModel<TEntity, TModel>(this TEntity entity)
    where TEntity : class
    where TModel : class, IViewModel<TEntity>, new()
{
    if (entity == null)
    {
        return null;
    }

    var model = new TModel();
    model.ToViewModel(entity);
    return model;
}
public interface IViewModel<in TEntity>
    where TEntity : class
{
    void ToViewModel(TEntity entity);
}

public class CompanyViewModel : IViewModel<Company>
{
    public Guid CompanyId { get; set; }

    public IList<CompanyUserViewModel> Users { get; set; }

    public void ToViewModel(Company entity)
    {
        CompanyId = entity.CompanyId;
        Users = entity.Users.ToViewModel<CompanyUser, CompanyUserViewModel>();
    }
}

public class CompanyUserViewModel : IViewModel<CompanyUser>
{
    public Guid CompanyId { get; set; }

    public Guid UserId { get; set; }

    public CompanyViewModel Company { get; set; }

    public UserViewModel User { get; set; }

    public void ToViewModel(CompanyUser entity)
    {
        CompanyId = entity.CompanyId;
        UserId = entity.UserId;
        Company = entity.Company.ToViewModel<Company, CompanyViewModel>();
        User = entity.User.ToViewModel<User, UserViewModel>();
    }
}

public class UserViewModel : IViewModel<User>
{
    public Guid UserId { get; set; }

    public void ToViewModel(User entity)
    {
        UserId = entity.Id;
    }
}

有没有办法防止这些引用被解析?

3 个答案:

答案 0 :(得分:1)

您愿意改变数据模型吗?我认为最好的解决方案是删除循环引用。

如果公司包含用户列表,那么用户是否还需要包含其所在的CompanyIdCompany对象?我将从您的public Company Company { get; set; }对象中删除CompanyUser,从您的Companies对象中删除User

答案 1 :(得分:1)

有多种解决方案:

1)您可以使用自动映射器代替自己的映射器。它具有MaxDepth属性,可以防止出现此问题:

Mapper.CreateMap<Source, Destination>().MaxDepth(1);

2)您可以从实体中删除依赖关系,并在一个方向上使用阴影属性。

答案 2 :(得分:1)

您的问题是,您要映射到CompanyViewModel,然后再映射到CompanyUserViewModel,但这又又映射回到CompanyViewModel,这将创建无限循环。

如果您希望始终从Company(到CompanyView)开始,则从CompanyUserViewModel删除递归。

public void ToViewModel(CompanyUser entity)
{
    CompanyId = entity.CompanyId;
    UserId = entity.UserId;
    // Company = entity.Company.ToViewModel<Company, CompanyViewModel>();
    User = entity.User.ToViewModel<User, UserViewModel>();
}

或者不要在您的ToViewModel映射中映射关系,而是根据ID将其关联起来。