NHibernate联接2个表并通过集合将项目投影到DTO

时间:2018-10-24 11:17:26

标签: nhibernate

我正在尝试连接2个表,并直接投影到DTO(NHibernate 5)。 我有以下实体:

public class Person {
    public Guid Id {get;set;}
    public string Name {get;set;}
}

public class Car {
    public Guid Id {get;set;}
    public string Brand {get;set;}
    public Person Owner {get;set;} 
}

如我们所见,Car到Person只是一个参考(car知道它的所有者),这在我的整个项目中都是可以的。

但是,在一个地方,我需要查询所有“人员”,并使每个人都拥有自己拥有的汽车。

我创建了这样的DTO:

public class PersonDto {
    public Guid Id {get;set;}
    public string Name {get;set;}
    public IList<CarDto> {get;set;}
}

public class CarDto {
    public Guid Id {get;set;}
    public string Brand {get;set;}
}

是一种呈现颠倒链接在一起的数据的形式。 使用SQL或LINQ(GroupJoin)执行此任务似乎微不足道,但由于在NH中未实现GroupJoin,因此我发现它在NH中极其困难。

能帮我解决上述问题吗?

2 个答案:

答案 0 :(得分:0)

只需将Car集合添加到现有的Person实体和mark the collection inverse。 NHibernate中的集合默认情况下是惰性的,因此,当您查询Person时,它将不会从数据库读取汽车,直到您开始对其进行迭代。换句话说,添加Car集合不会影响代码的工作方式。

当您想有效地查询汽车的相关人员时,请强制NH进行加入

.QueryOver<Person>.Fetch(person => person.Cars).Eager

答案 1 :(得分:0)

我想回答我自己的问题。感谢Rafal Rutkowski的投入。

要获取仅在1个方向上具有关联的数据,我们需要引入一个新的数据模型,然后将结果手动转换为我们的实体。我希望以下示例是最好的答案:

1)创建此类数据模型以存储NH响应:

private class PersonCarModelDto
{
    public Guid PersonId { get; set; }
    public string PersonName { get; set; }
    public Guid CarId { get; set; }
    public string CarBrand { get; set; }
}

2)创建一个这样的模型来存储分层数据作为输出:

private class PersonModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public IList<CarModel> Cars { get; set; }
}

private class CarModel
{
    public Guid Id { get; set; }
    public string Brand { get; set; }
}

3)现在是NH查询:

Person personAlias = null;
Car carAlias = null;
PersonCarModelDto resultAlias = null;

var response = GetCurrentSession().QueryOver<Car>(() => carAlias) // notice we are going from from 'downside' entity to 'up'
    .Right.JoinAlias(c => c.Owner, () => personAlias) // notice Right join here, to have also Persons without any car
    .SelectList(list => list
        .Select(() => personAlias.Id).WithAlias(() => resultAlias.PersonId)
        .Select(() => personAlias.Name).WithAlias(() => resultAlias.PersonName)
        .Select(() => carAlias.Id).WithAlias(() => resultAlias.CarId)
        .Select(() => carAlias.Brand).WithAlias(() => resultAlias.CarBrand)
    .TransformUsing(Transformers.AliasToBean<PersonCarModelDto>())
    .List<PersonCarModelDto>()
    ;

4)现在我们将平面数据作为PersonCarModelDto的列表,但我们要创建输出模型:

var modelResult = response.GroupBy(p => p.PersonId)
    .Select(x => new PersonModel
    {
        Id = x.Key,
        Name = x.Select(y => y.PersonName).First(), // First() because each PersonName in that group is the same
        Cars = x.Select(y => new CarModel
        {
            Id = y.CarId,
            Name = y.CarBrand
        })
        .ToList()
    })
    .ToList()
    ;

结论:

  • 具有双向关联的问题更容易解决
  • 如果由于某种原因,您不希望进行双向关联,请使用此技术
  • 如果您的实体还有很多其他属性,这种方法也很有用,但是由于某种原因,您只需要其中的一小部分 (为DB返回的数据进行优化)