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);