如何通过StatelessSession仅加载根实体及关联实体ID(Banan查询)
Solution for Querying Banan Subclasses with Only Root Entities and Associated IDs in NHibernate
Based on your existing implementation for FatherBanan and JobBanan, here's how you can build an extension method to support sss.Query<Banan>().ToOnlyRefList() that loads only the root entity data and associated entity IDs (no full entity loading), even with polymorphic types and any associations.
Key Considerations
Bananis an abstract base class withFatherBananandMotherBanansubclasses- Each subclass has an
anyassociation (WifeBanan for Father, HusbandBanan for Mother) that we need to fetch only the ID and type for - We need to avoid full entity loading and keep SQL queries efficient
Implementation
First, create a helper method to generate lightweight Banan references (only ID populated):
private static Banan CreateBananRef(long id, string typeName) { return typeName switch { nameof(FatherBanan) => new FatherBanan { Id = id }, nameof(MotherBanan) => new MotherBanan { Id = id }, _ => throw new ArgumentException($"Unrecognized Banan subtype: {typeName}") }; }
Then, implement the ToOnlyRefList extension for IQueryOver<Banan, Banan> (more reliable for handling polymorphic and any associations than LINQ IQueryable):
public static List<Banan> ToOnlyRefList(this IQueryOver<Banan, Banan> query) { var result = new List<Banan>(); // Process FatherBanan instances var fatherResults = query.OfType<FatherBanan>() .SelectList(select => select .Select(f => f.Id) .Select(f => f.Name) .Select(f => f.Variety) .Select(f => f.VersionObject) // Directly fetch the any association's ID and type from the database table .Select(Projections.SqlProjection( "Banan_Id as WifeId", new[] { "WifeId" }, new IType[] { NHibernateUtil.Int64 })) .Select(Projections.SqlProjection( "Banan_Type as WifeType", new[] { "WifeType" }, new IType[] { NHibernateUtil.String })) ) .List<object[]>(); foreach (var item in fatherResults) { result.Add(new FatherBanan { Id = (long)item[0], Name = (string)item[1], Variety = (string)item[2], VersionObject = (long)item[3], WifeBanan = CreateBananRef((long)item[4], (string)item[5]) }); } // Process MotherBanan instances var motherResults = query.OfType<MotherBanan>() .SelectList(select => select .Select(m => m.Id) .Select(m => m.Variety) .Select(m => m.VersionObject) // Directly fetch the any association's ID and type from the database table .Select(Projections.SqlProjection( "Banan_Id as HusbandId", new[] { "HusbandId" }, new IType[] { NHibernateUtil.Int64 })) .Select(Projections.SqlProjection( "Banan_Type as HusbandType", new[] { "HusbandType" }, new IType[] { NHibernateUtil.String })) ) .List<object[]>(); foreach (var item in motherResults) { result.Add(new MotherBanan { Id = (long)item[0], Variety = (string)item[1], VersionObject = (long)item[2], HusbandBanan = CreateBananRef((long)item[3], (string)item[4]) }); } return result; }
Usage
You can use this extension with both regular sessions and stateless sessions:
Regular Session
using (var session = factorySession.OpenSession()) { var allBanans = session.QueryOver<Banan>().ToOnlyRefList(); }
Stateless Session
using (var statelessSession = factorySession.OpenStatelessSession()) { var allBanans = statelessSession.QueryOver<Banan>().ToOnlyRefList(); }
Why This Works
- Polymorphic Handling:
OfType<T>filters the query to target each subclass individually, allowing us to handle their specific fields and associations. - Efficient SQL: Using
SqlProjectiondirectly fetches theanyassociation's ID and type from the subclass table, avoiding unnecessary joins or full entity loading. The generated SQL will only query the columns you need from each subclass table. - Lightweight References: The
CreateBananRefmethod creates minimal subclass instances with only the ID populated, matching your requirement of loading only associated IDs instead of full entities.
Notes
- Ensure the column names in
SqlProjectionmatch exactly with your database schema (e.g.,Banan_IdandBanan_Typeas defined in your HBM mappings). - The type name strings must match the
meta-valueentries in your HBM mappings (we usenameof()here to keep it type-safe and avoid typos).
内容的提问来源于stack exchange,提问作者SoftStone
相关产品推荐
相关产品推荐

