C# 具有自定义实体viewmodel映射器的循环依赖项

C# 具有自定义实体viewmodel映射器的循环依赖项,c#,mapping,C#,Mapping,假设我有Patient和Cycle域实体,我正在通过EF加载它们: public class Patient { public int PatientId { get; set; } public string Name { get; set; } public List<Cycle> Cycles { get; set; } public Patient() { Cycles = new List<Cycle>

假设我有
Patient
Cycle
域实体,我正在通过EF加载它们:

public class Patient
{
    public int PatientId { get; set; }
    public string Name { get; set; }

    public List<Cycle> Cycles { get; set; }

    public Patient()
    {
        Cycles = new List<Cycle>();
    }
}

public class Cycle
{
    public int CycleId { get; set; }
    public int PatientId { get; set; }
    public bool IsActive { get; set; }

    public Patient Patient { get; set; }
}
如您所见,我需要注入一个
CycleMapper
。在
CycleMapper
中,我需要注入
PatientMapper
的实例来映射
Patient
导航属性。这会导致循环DI问题

我在过去通过创建每个实体的“基本”版本解决了这个问题。例如,
BasicCycle
将没有
Patient
导航属性。这是可行的,但需要更多的实体、映射器等


有更好的方法吗?

所以这里有两个问题:构造函数中的递归依赖注入和递归映射。要解决递归DI,有几个选项。首先是将对象工厂而不是对象本身传递给构造函数。Autofac本机支持:

private readonly Func<IPatientMapper> patientMapper;
public CycleMapper(Func<IPatientMapper> patientMapper)
{
    this.patientMapper = patientMapper;
}
然后像这样注册(所有地图绘制者):


像往常一样,不再关心循环依赖项。

而不是注入实例-注入工厂(
Func
或自定义工厂)。@Evk感谢您的回复。我没有完全理解。你能发布一个kopy.io吗?你需要绑定到它的患者之外的“周期”吗?如果不是,那么为什么不在CycleMapper中用一个新的定义(如CycleMapper.GetViewModel(patient))更改GetViewModel定义呢。据我所知,您的周期只需要一个病人实例来填充它的病人导航属性。@Alaminut根据情况,我可能正在查询一个周期,在这种情况下,我可能想了解病人,或者我可能正在查询一个想了解其周期的病人。您说过问题是循环DI。为了避免这种情况,不要注入ICycleMapper的实例,而是在需要时注入一种创建新实例的方法(工厂)。有些容器不需要额外的努力就可以做到这一点,对于其他容器,您需要自己创建工厂。你用哪个容器?
private readonly Func<IPatientMapper> patientMapper;
public CycleMapper(Func<IPatientMapper> patientMapper)
{
    this.patientMapper = patientMapper;
}
public IPatientMapper PatientMapper { get; set; }
builder.RegisterType<CycleMapper>().As<ICycleMapper>().SingleInstance().PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);
public interface IPatientMapper {
    PatientViewModel GetViewModel(Patient patient, IDictionary<object, object> map = null);
}

public interface ICycleMapper {
    CycleViewModel GetViewModel(Cycle cycle, IDictionary<object, object> map = null);
}

public class CycleMapper : ICycleMapper
{
    public IPatientMapper PatientMapper { get; set; }

    public CycleViewModel GetViewModel(Cycle cycle, IDictionary<object, object> map = null)
    {
        if (cycle == null) {
            return null;
        }
        // If called without map - create new one
        if (map == null)
            map = new Dictionary<object, object>();
        // if we already mapped this cycle before - don't do this again
        // and instead return already mapped entity
        if (map.ContainsKey(cycle))
            return (CycleViewModel)map[cycle];

        var viewModel = new CycleViewModel();
        viewModel.PatientId = cycle.PatientId;
        viewModel.CycleId = cycle.CycleId;
        viewModel.IsActive = cycle.IsActive;
        // add this entity to map before calling any other mappers
        map.Add(cycle, viewModel);
        // pass map to other mapper
        viewModel.Patient = PatientMapper.GetViewModel(cycle.Patient, map);
        return viewModel;
    }
}
var model = mapper.GetViewModel(patient);