简体   繁体   中英

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 Table1 s. I also want to select all Table2 s that meet a certain criteria ( Table2.Field = 'value' ), but I don't want to limit my Table1 s, so select null Table2 s 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 Table1 s, and within each Table1 I'd like either an empty list of Table2 s (because no Table2 s met the criteria), or a list of Table2 s 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();

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 .

There is pretty good documentation - 16.4. Associations

http://nhibernate.info/doc/nh/en/index.html#queryqueryover-associations

The QueryOver syntax would look like this

IQueryOver<Table1, Table2> myQuery = 
  session.QueryOver<Table1>()
   .Left.JoinQueryOver<Table2>(t => t.Table2s)
     .Where(
       Restrictions.Or(
         Restrictions.On<Table2>((t2) => t2.ID).IsNull, 
         Restrictions.On<Table2>((t2) => t2.Field).IsLike("value")
         )
       );
var list = myQuery.List<Table1>();

then the list will return the collection of all combinations meeting the criteria. (Later order by or distinct or other porjections could be added...)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM