QueryOver — я думал, идентификаторы были бесплатными?

#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)]
  

Именно (я думаю) то, что я хотел.