NHibernate 加入 2 个表并使用集合项目到 DTO

NHibernate join 2 tables and project to DTO with collection

我正在尝试连接 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 的引用(汽车知道它的主人),这在我的整个项目中都是可以的。

但是,有一个地方,我需要查询所有的人,并让每个人拥有拥有的汽车。

我创建了这样的 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 中实现。

你能帮我解决上面的问题吗?

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

想高效查询人和车时,强制NH做join

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

我想回答我自己的问题。感谢 Rafal Rutkowski 的意见。

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

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

结论:

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