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()
;
结论:
- 有了双向关联,问题就更容易解决了
- 如果出于某种原因,您不想双向关联,请使用此技术
- 如果您的实体有很多其他属性,但由于某种原因您只需要其中的一小部分,这种方法也很有用
(为数据库返回的数据优化)
我正在尝试连接 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()
;
结论:
- 有了双向关联,问题就更容易解决了
- 如果出于某种原因,您不想双向关联,请使用此技术
- 如果您的实体有很多其他属性,但由于某种原因您只需要其中的一小部分,这种方法也很有用 (为数据库返回的数据优化)