有没有办法在动态选择中传递我想要从数据库中检索的属性,我事先并不知道我需要的属性,我不想在我的存储库中写入条件。
我不想一次检索所有字段,只根据某些条件检索我需要的字段。
例如:
public class Student
{
public string Property1 {get; set;}
public string Property2 {get; set;}
//other properties here
[NotMapped]
public string Selected
{
if(condition)
return Property1;
else
return Property2;
}
}
在服务层我有
query.Select(s => new StudentViewModel
{
Value = s.Selected; //this one will get the property we want based on a condition
//other stuff here
//OtherValue = s.OtherProperty
}
).FirstOrDefault();
答案 0 :(得分:0)
<强>选择强>
一种简单但丑陋的方式是使用选择器:
var popup = window.open("https://www.google.com", "popup_window", "fullscreen");
if (popup.outerWidth < screen.availWidth || popup.outerHeight < screen.availHeight)
{
popup.moveTo(0,0);
popup.resizeTo(screen.availWidth, screen.availHeight);
}
选择器看起来像这样:
query.Select(Selector()).FirstOrDefault();
正如您所看到的,明显的缺点是您需要复制/粘贴所有其他选定的属性。这就是它丑陋的原因。
<强> AutoMapper 强>
<强> CONFIGS 强>
您可以使用不同配置的AutoMapper。首先,您需要为所有不需要动态的属性定义标准映射。
private static Expression<Func<Student, StudentViewModel>> Selector()
{
if (Condition())
return x => new StudentViewModel
{
Name = x.Property1,
OtherName = x.OtherName
};
return x => new StudentViewModel
{
Name = x.Property2,
OtherName = x.OtherName
};
}
接下来,您需要定义不同的配置并将public static void AddStandardStudentMap(this IMappingExpression<Student, StudentViewModel> map)
{
map.ForMember(dest => dest.OtherName, opt => opt.MapFrom(src => src.OtherProperty))
.ForMember(dest => dest.OtherName2, opt => opt.MapFrom(src => src.OtherProperty2));
// you can concat .ForMember() for each property you need.
}
方法添加到每个invidual映射。
AddStandardStudentMap
在此之后,只需使用您的条件来决定您需要哪个配置
var config1 = new MapperConfiguration(cfg =>
cfg.CreateMap<Student, StudentViewModel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Property1))
.AddStandardStudentMap()
);
var config2 = new MapperConfiguration(cfg =>
cfg.CreateMap<Student, StudentViewModel>()
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Property2))
.AddStandardStudentMap()
);
而不是IConfigurationProvider provider;
if(Condition())
provider = config1;
else
provider = config2;
使用:
.Select()
正如我们所看到的,这个解决方案仍然很丑陋并且有很多开销,但在某些情况下需要它,这就是我在这里说的原因。
<强>表达式强>
这有点类似于Configs,但为您带来更多灵活性和更少的写作努力。
首先创建配置,但这次使用选择器
query.ProjectTo<StudentViewModel>(provider).FirstOrDefault();
Selector方法如下所示:
var config = new MapperConfiguration(cfg =>
cfg.CreateMap<Student, StudentViewModel>()
.ForMember(dest => dest.OtherName, opt => opt.MapFrom(src => src.OtherName))
.ForMember(dest => dest.OtherName2, opt => opt.MapFrom(src => src.OtherName2))
// and so on. Map all your properties that are not dynamically.
// and then the Selector
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => Selector()))
);
然后就像配置解决方案一样使用它,但不选择特定的配置:
private static Expression<Func<Student, StudentViewModel>> Selector()
{
if(Condition())
return src => src.Property1;
else
return src => src.Property2;
}
<强>结论强>
我知道这是很多输入,无论有没有AutoMapper,都有更多可能实现你想要的行为。但我建议你(基于你给我们的信息)使用AutoMapper和Expressions。它应该提供您所需的灵活性,并且可以扩展以满足进一步的要求。