#nhibernate #subquery #queryover
#nhibernate #подзапрос #запрос
Вопрос:
Мне потребовалось некоторое время, но я понял, как получить то, что я хочу — в основном. Мой код:
var sq = QueryOver.Of<VehicleGroup>(() => vehicleGroup)
.JoinQueryOver<Manager>(vg => vg.Managers)
.Where(man => man.Id == managerId)
.JoinQueryOver<TruckPCBase>(() => vehicleGroup.Vehicles)
.Where(v => v.Id == item.VehicleId)
.Select(vg => vg.Id)
;
var vp = Session.QueryOver<Summary>(() => item)
.WithSubquery.WhereExists(sq)
.Take(10)
.List();
Это возвращает именно то, что я хочу.
ОДНАКО мне пришлось сопоставить дополнительное поле, чтобы оно работало.
У сводного объекта есть компонент VehicleBase. Что я хотел сделать, так это:
var sq = QueryOver.Of<VehicleGroup>(() => vehicleGroup)
.JoinQueryOver<Manager>(vg => vg.Managers)
.Where(man => man.Id == managerId)
.JoinQueryOver<TruckPCBase>(() => vehicleGroup.Vehicles)
.Where(v => v.Id == item.VehicleBase.Id)
.Select(vg => vg.Id)
;
var vp = Session.QueryOver<Summary>(() => item)
.WithSubquery.WhereExists(sq)
.Take(10)
.List();
Это выдает следующую ошибку:
System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method(ExecutionScope )
Хорошо, поэтому я добавил дополнительную выборку:
var sq = QueryOver.Of<VehicleGroup>(() => vehicleGroup)
.JoinQueryOver<Manager>(vg => vg.Managers)
.Where(man => man.Id == managerId)
.JoinQueryOver<TruckPCBase>(() => vehicleGroup.Vehicles)
.Where(v => v.Id == item.VehicleBase.Id)
.Select(vg => vg.Id)
;
var vp = Session.QueryOver<Summary>(() => item)
.Fetch(sum => sum.VehicleBase).Eager
.WithSubquery.WhereExists(sq)
.Take(10)
.List();
Нет кубиков. Я не хочу добавлять новое свойство в свой сводный класс (VehicleId) — я хочу получить к нему доступ через Summary.VehicleBase.Id
Предложения?
Ответ №1:
Я не мог полностью понять, что вы пытаетесь сделать, однако проблема, похоже, заключается в :
вы получаете это исключение, потому что для этой строки
.Where(v => v.Id == item.VehicleBase.Id)
item
равно нулю.
Вычислитель выражений linq для nhibernate попытается с готовностью оценить все, что не включает параметр lambda. Для этого случая:
v.Id =>
будет оценено позже и обращено к HQL item.VehicleBase.Id =>
без зависимости v
, поэтому оценщик с нетерпением оценит его, что приведет к NRE.
Комментарии:
1. Итак, как мне настроить зависимость?
Ответ №2:
Заставил это работать!!!
var sq = QueryOver.Of<VehicleGroup>()
.Inner.JoinAlias(vg => vg.Managers, () => manager)
.Where(() => manager.Id == managerId)
.JoinQueryOver(x => x.Vehicles, () => vehicle)
.Select(x => vehicle.Id)
;
var vp = Session.QueryOver<Summary>()
.Fetch(vpr => vpr.VehicleBase).Eager
.WithSubquery.WhereProperty(x => x.VehicleBase.Id).In(sq)
.Take(10)
.List()
;
Это генерирует следующий SQL
SELECT
TOP (@p0) this_.summaryID as summaryID42_1_,
... close to 200 columns cut ...
FROM
dbo.Summary this_
left outer join
dbo.Vehicle vehiclebas2_
on this_.VehicleID = vehiclepcbas2_.VehicleID
WHERE
this_.vehicleID in (
SELECT
vehicle2_.vehicleID as y0_
FROM
dbo.Groups this_0_
inner join
dbo.Manager_Rel managers4_
on this_0_.groupId=managers4_.groupId
inner join
dbo.Managers manager1_
on managers4_.managerId=manager1_.ManagerId
inner join
dbo.Object_Rel vehicles6_
on this_0_.groupId=vehicles6_.groupId
inner join
dbo.Vehicle vehicle2_
on vehicles6_.ID=vehicle2_.VehicleID
WHERE
this_0_.type=1
AND manager1_.ManagerId = @p1
);
@p0 = 10 [Type: Int32 (0)], @p1 = 34 [Type: Int32 (0)]
Именно (я думаю) то, что я хотел.