如何将 IQueryable 转换为“表达式”<Func" to provide Projection list to NHibernate QueryOver?

问题描述 投票:0回答:1

请参考以下代码:

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
方法并向其传递适当的参数。
这会工作得很好;但这种方法几乎没有问题:

  • 我必须输入每个投影/表达式作为这些方法的输入。
  • 如果我以后更改 Dto,我应该记得更改投影列表。

所以,我在想上面代码中提到的一些事情。这可能吗?还有其他类似/更简单的解决方案吗?

nhibernate projection iqueryable queryover projectto
1个回答
0
投票

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); });
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.