问题
I have the following entities
public class Vehicle
{
public virtual string InternalNumber { get; set; }
public virtual IList<VehicleDriverHistory> DriverHistory { get; set; }
}
public class VehicleDriverHistory : HistoryEntity
{
public virtual Vehicle Vehicle { get; set; }
public virtual DriverPerson Driver { get; set; }
public virtual DateTime Date { get; set; }
}
Now I need to select every Vehicle and, if present, the newest VehicleDriverHistory-Entry according to "Date". But I'm kinda struggling, I have no problem doing it in sql, but failed in nhibernate so far.
What I have so far:
VehicleDriverHistory vdHistory = null;
VehicleDriverHistory vdHistory2 = null;
q.Left.JoinAlias(x => x.DriverHistory, () => vdHistory);
q.Left.JoinAlias(x => x.DriverHistory, () => vdHistory2).Where(x => vdHistory2.Date > vdHistory.Date);
q.Where(x => vdHistory2.Id == null);
This doesn't work and it was just my attempt to "translate" the sql query (which yields the correct data) to nhibernate.
So, how would I select parents and the newest child (or none if none is present)
Thanks
UPDATE
With Firos help I ended up with the following:
VehicleDriverHistory historyAlias = null;
var maxDateQuery = QueryOver.Of<VehicleDriverHistory>()
.Where(h => h.Vehicle == historyAlias.Vehicle)
.Select(Projections.Max<VehicleDriverHistory>(h => h.Date));
var vehiclesWithEntry = DataSession.Current.QueryOver(() => historyAlias)
.WithSubquery.WhereProperty(h => h.Date).Eq(maxDateQuery)
.Fetch(h => h.Vehicle).Eager
.Future();
Vehicle VehicleAlias = null;
var vehiclesWithoutEntry = DataSession.Current.QueryOver<Vehicle>(() => VehicleAlias)
.WithSubquery
.WhereNotExists(QueryOver.Of<VehicleDriverHistory>()
.Where(x => x.Vehicle.Id == VehicleAlias.Id).Select(x => x.Id))
.Future();
return vehiclesWithEntry.Select(h => new PairDTO { Vehicle = h.Vehicle, NewestHistoryEntry = h }).Concat(vehiclesWithoutEntry.Select(v => new PairDTO { Vehicle = v })).ToList();
I had to replace the Any() statement in vehclesWithoutEntry with a subquery-clause because it raised an exception.
回答1:
some other idea using Futures to make only one roundtrip
VehicleDriverHistory historyAlias = null;
var maxDateQuery = QueryOver.Of<VehicleDriverHistory>()
.Where(h => h.Vehicle == historyAlias.Vehicle)
.Select(Projections.Max<VehicleDriverHistory>(h => h.Date));
var vehiclesWithEntry = session.QueryOver(() => historyAlias)
.WithSubquery.WhereProperty(h => h.Date).Eq(maxDateQuery)
.Fetch(h => h.Vehicle).Eager
.Select(h => new PairDTO { Vehicle = h.Vehicle, NewestHistoryEntry = h })
.Future<PairDTO>();
var vehiclesWithoutEntry = session.QueryOver<Vehicle>()
.Where(v => !v.DriverHistory.Any())
.Select(v => new PairDTO{ Vehicle = v })
.Future<PairDTO>();
return vehiclesWithoutEntry.Concat(vehiclesWithEntry); // .ToList() if immediate executing is required
Update: i can not reproduce the exception but you could try this
VehicleDriverHistory historyAlias = null;
var maxDateQuery = QueryOver.Of<VehicleDriverHistory>()
.Where(h => h.Vehicle == historyAlias.Vehicle)
.Select(Projections.Max<VehicleDriverHistory>(h => h.Date));
var vehiclesWithEntry = session.QueryOver(() => historyAlias)
.WithSubquery.WhereProperty(h => h.Date).Eq(maxDateQuery)
.Fetch(h => h.Vehicle).Eager
.Future();
var vehiclesWithoutEntry = session.QueryOver<Vehicle>()
.Where(v => !v.DriverHistory.Any())
.Select(v => new PairDTO{ Vehicle = v })
.Future<PairDTO>();
return vehiclesWithoutEntry.Select(h => new PairDTO { Vehicle = h.Vehicle, NewestHistoryEntry = h }).Concat(vehiclesWithEntry);
来源:https://stackoverflow.com/questions/11241560/nhibernate-select-parents-and-newest-child