Betrachten Sie diese erfundene Domäne sortieren:NHibernate QueryOver jeder der Eins-zu-viele Sammlungen
namespace TryHibernate.Example {
public class Computer
{
public int Id { get; set; }
public IList<Device> Devices { get; set; }
}
public class Device
{
public int Id { get; set; }
public Maker Maker { get; set; }
}
public class Maker
{
public int Id { get; set; }
public string Name { get; set; }
}
} // namespace
Wenn ich nur alle Computer abfragen, werden ihre Geräte zufällig bestellt werden. Ich möchte sie nach dem Namen des Herstellers bestellen lassen. Ich kann es wirklich nicht mit HasMany().OrderBy()
tun, weil, soweit ich sagen kann OrderBy
kann nur lokale Spalten verwenden (so kann ich es zum Beispiel durch Device.Id
sortieren). Außerdem wäre es nett, die Reihenfolge pro Abfrage zu steuern, also suche ich nach einer QueryOver
Lösung.
Die weitest ich bekommen konnte, war dies:
using (ISessionFactory sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard.UsingFile("temp.sqlite").ShowSql())
.Mappings(m => m.AutoMappings.Add(
AutoMap.AssemblyOf<Computer>(new ExampleConfig())
.Conventions.Add(DefaultLazy.Never())
.Conventions.Add(DefaultCascade.All())))
.ExposeConfiguration(c => new SchemaExport(c).Create(true, true))
.BuildSessionFactory())
{
using (ISession db = sessionFactory.OpenSession())
{
Computer comp = new Computer();
comp.Devices = new List<Device>();
Device dev1 = new Device();
comp.Devices.Add(dev1);
dev1.Maker = new Maker() { Name = "IBM"};
Device dev2 = new Device();
comp.Devices.Add(dev2);
dev2.Maker = new Maker() { Name = "Acer"};
db.Persist(comp);
db.Flush();
}
using (ISession db = sessionFactory.OpenSession())
{ // This is the part I'm having trouble with:
Device devAlias = null;
Maker makerAlias = null;
IList<Computer> comps = db.QueryOver<Computer>()
.JoinAlias(c => c.Devices,() => devAlias)
.JoinAlias(() => devAlias.Maker,() => makerAlias)
.OrderBy(() => makerAlias.Name).Asc
.List();
Console.WriteLine(comps.Count);
foreach (Device dev in comps[0].Devices)
{
Console.WriteLine(dev.Maker.Name);
}
}
}
Aber natürlich ist es nicht tun, was ich will. Es versucht, die ganze Liste nach dem Namen des Herstellers zu sortieren. Es ist auch erfolgreich, wie ich aus der SQL sehen kann, und ich bekomme tatsächlich ein nutzloses kartesisches Produkt von Computern mit Geräten, die vom Gerätehersteller sortiert wurden.
Aber dann gibt es eine andere SQL-Abfrage, um die Geräte zu holen, dieses Mal ohne zu sortieren. Ich denke, NHibernate hat keine Ahnung, dass meine Joins die Kinder holen sollen.
Die Frage ist, wie kann ich diese zweite Abfrage steuern? Zum Beispiel, um Geräte nach dem Namen des Herstellers zu bestellen, oder um jede Computer.Devices
Liste zu erhalten, die nur Geräte enthält, die beispielsweise von IBM (falls vorhanden) hergestellt wurden. Ich denke, ich brauche dafür eine Unterabfrage, aber wo stecke ich sie an?
Nur der Vollständigkeit halber, hier ist meine config:
class ExampleConfig : DefaultAutomappingConfiguration
{
public override bool ShouldMap(Type type)
{
return type.Namespace == "TryHibernate.Example";
}
}
"Es scheint zu viel Arbeit zu sein, nur etwas zu bestellen, was SQL out-of-the-box unterstützt" - stimme völlig zu. Es sollte einfacher sein, aber es ist nicht so. NHibernate hat oft diese Fähigkeit, sowohl reif als auch ... dumm zugleich zu sein; Ganz zu schweigen von der Dokumentationsqualität ... Allerdings gibt es LINQ-Unterstützung in NH. Hast du das gesehen? –
@Bozhidar, richtig, ich habe Linq gesehen, aber ich bin mir nicht sicher, ob es in diesem Fall verwendet werden kann, und ich bin mir nicht sicher, ob es sich um SQL oder In-Memory-Sortierung handelt, was sinnlos ist da kann ich das immer selbst auf der abgeholten Sammlung machen. –