请参考以下代码:
using(ISession session = SessionFactory.OpenSession())
{
//Case 1: using Query = works fine.
IList<MasterDto> listMaster = session.Query<MasterEntity>()
.ProjectTo<MasterDto>(autoMapperConfig)
.ToList();
//Case 2: using QueryOver = how to achieve same result as above?
IQueryable<MasterDto> masterDtos = session.Query<MasterEntity>()
.ProjectTo<MasterDto>(autoMapperConfig);
IList<MasterEntity> list = session.QueryOver<MasterEntity>()
.Select(masterDtos)//This of-course does not work
.List();
}
如果我在案例 2 中注释
Select(masterDtos)
,以上两种情况都会返回相同的结果。其他区别是生成的 SQL 查询。
在上面的情况 1 中,生成的 SQL 仅包含 Dto 中存在的列。它会跳过 Entity 中存在但 Dto 中不存在的附加列。这对于提高 SQL 查询性能是必要的。
传递给
autoMapperConfig
方法的 ProjectTo
参数有 AutoMapper.MapperConfiguration
的实例。
案例 1 工作正常。
但是我有大量使用
QueryOver
的遗留代码。QueryOver
迁移到 Query
NHibernate API 非常困难且容易出错。
所以,我正在考虑如何使用
QueryOver
来实现这一目标(选择选定的列)。Select
和/或 SelectList
的 QueryOver
方法并向其传递适当的参数。所以,我在想上面代码中提到的一些事情。这可能吗?还有其他类似/更简单的解决方案吗?
Query
和QueryOver
是两个不同的东西。他们以不同的方式工作。对于 QueryOver
,您必须使用 Select
和/或 SelectList
的 QueryOver
方法,正如您在问题中指出的那样。
对于
Query
(返回 IQueryable
),ProjectTo
接受类型为 IConfigurationProvider
的参数,您将其作为 autoMapperConfig
提供。因此,你的第一个案例有效。
您的第二种情况完全错误,因为传递给
Select
方法的参数与类型不匹配。
以下代码与您的第一个案例类似并且可以正常工作:
var autoMapperConfig = new MapperConfiguration
(
cfg =>
{
cfg.CreateProjection<MasterEntity, MasterDto>();
cfg.CreateProjection<DetailEntity, DetailDto>()
.ForMember(dto => dto.MasterData, conf => conf.MapFrom(ol => ol.Master.MasterData));
cfg.CreateProjection<DetailEntity, DetailMiniDto>();
}
);
using(ISession session = SessionFactory.OpenSession())
{
IList<MasterDto> listMaster = session.Query<MasterEntity>()
.Where(x => x.MasterId == 1)
.ProjectTo<MasterDto>(autoMapperConfig)
.ToList();
IList<DetailDto> listDetail = session.Query<DetailEntity>()
.Where(x => x.Master.MasterId == 1)
.ProjectTo<DetailDto>(autoMapperConfig)
.ToList();
}
以下是
MasterEntity
、MasterDto
和MasterMap
:
public class MasterEntity
{
public virtual int MasterId { get; set; }
public virtual string MasterData { get; set; }
public virtual IList<DetailEntity> DetailList { get; set; }
}
public class MasterDto
{
public string MasterData { get; set; }
public IList<DetailMiniDto> DetailList { get; set; }
}
internal class MasterMap : ClassMapping<MasterEntity>
{
public MasterMap()
{
Table("MasterTable");
Id(x => x.MasterId, im =>
{
im.Column("MasterId");
im.Generator(Generators.Identity);
});
Property(x => x.MasterData, map => { map.Type(TypeFactory.GetAnsiStringType(5)); });
Bag
(
x => x.DetailList,
map =>
{
map.Key(k => k.Column("MasterId"));
},
rm => rm.OneToMany()
);
}
}
以下是
DetailEntity
、DetailDto
、DetailMiniDto
和DetailMap
:
public class DetailEntity
{
public virtual int DetailId { get; set; }
public virtual string DetailData { get; set; }
public virtual MasterEntity Master { get; set; }
}
public class DetailDto : DetailMiniDto
{
public string MasterData { get; set; }
}
public class DetailMiniDto
{
public int DetailId { get; set; }
public string DetailData { get; set; }
}
internal class DetailMap : ClassMapping<DetailEntity>
{
public DetailMap()
{
Table("DetailTable");
Id(x => x.DetailId, im =>
{
im.Column("DetailId");
im.Generator(Generators.Identity);
});
Property(x => x.DetailData);
ManyToOne(x => x.Master, map => { map.Column("MasterId"); map.Cascade(Cascade.None); });
}
}