Search code examples
c#.netnhibernateleft-joinfluent

Limit child entities without limiting parent entities - NHibernate


I'm trying to limit the result set of a mapped collection.

Here is a simple model:

public class Table1 {
    public virtual long Id { get; set; }
    public virtual IList<Table2> Table2s { get; set; }
}


public class Table2 {
    public virtual long Id { get; set; }
    public virtual long Table1Id { get; set; }
    public virtual Table1 Table1 { get; set; }
    public virtual string Field { get; set; }
}

public class Table1Map : ClassMap<Table1> {
    public Table1Map () {
        Table("Table1");
        Id(x => x.Id).Column("Id").Not.Nullable().CustomType("Int64").GeneratedBy.Native();
        HasMany<Table2>(x => x.Table2s).Inverse().Not.LazyLoad().KeyColumns.Add("Table1Id").Fetch.Join();
    }
}

public class Table2Map : ClassMap<Table2> {
    public Table2Map () {
        Table("Table2");
        Id(x => x.Id).Column("Id").Not.Nullable().CustomType("Int64").GeneratedBy.Native();
        Map(x => x.Table1Id).Column("Table1Id").Not.Nullable().CustomType("Int64");
        Map(x => x.Field).Column("Field").Not.Nullable().CustomType("AnsiString").Length(25);
        References<Table1>(x => x.Table1, "Table1Id").Cascade.None();
    }
}

I want to select all Table1s. I also want to select all Table2s that meet a certain criteria (Table2.Field = 'value'), but I don't want to limit my Table1s, so select null Table2s if they don't meet the criteria. If I want to do this in SQL I'd do the following:

SELECT *
FROM 
Table1
LEFT OUTER JOIN Table2 ON Table1.Id = Table2.Table1Id
WHERE
Table2.Field = 'value' or Table2.Field IS NULL

How should I structure my NHibernate query to achieve the desired result? I'd like a list of Table1s, and within each Table1 I'd like either an empty list of Table2s (because no Table2s met the criteria), or a list of Table2s that met the creteria.

I'm trying something like the following, but this will obviously not work:

List<Table1> result = new List<Table1>();
IQueryable<Table1> query = session.Query<Table1>();
if (value != null) {
    query = query.Where(x => x.Table2s.Field == value);
}
query = query.OrderBy(x => x.Id);
result = query.ToList();

Solution

  • I think this is not possible the way you do this. Hibernate loads the complete entity with all its properties (if not lazyloading is activated). What should hibernate do, if you save such a loaded entity of type table1 without all table2's?

    You should create some kind of viewobject (dvo) that contains the relevant parts of table1 and a list of table2 childs that fit the criteria. The select could possible be done by projection.