fetching strategies for collections of abstract type

杀马特。学长 韩版系。学妹 提交于 2019-12-02 11:51:39

When using JoinQueryOver or JoinAlias NHibernate won't initialize the collection because you could/do filter out Terms so there might be not all Terms fetched which are in the Terms collection. The only way i can think of is a subquery.

var subquery = QueryOver.For<SearchDefinition>()
   .Where(/*conditions*/)
   .JoinAlias(d=> d.Terms, () => termsAlias)
   .Where(/*Terms.conditions*/)
   .Select(def => def.Id);

var definitions = session.QueryOver<SearchDefinition>()
   .WithSubquery.WhereProperty(def => def.Id).In(subquery);
   .List();

Assert.IsTrue(NHibernateUtil.IsInitialized(definitions[0].Terms));

the thing is that once the fetching strategy in the mapping file is defined as 'SubSelect', initializing one type of collection would initialize it on all objects that contain that type of collection.
See the follwing working code for further details:

    var subQuery = QueryOver.Of<SearchDefinition>()
        .Where(p => p.IsActive)
        .Select(p => p.Id);

    var searchDefinitionsQuery = Session.QueryOver<SearchDefinition>()
        .WithSubquery.WhereProperty(p => p.Id).In(subQuery);
        searchDefinitionsQuery.OrderBy(p => p.SortOrder).Asc();

    var searchDefinitionsWithTerms = searchDefinitionsQuery.Future();

    var intValuesQuery = Session.QueryOver<IntValuesTerm>()
        .WithSubquery.WhereProperty(c => c.SearchDefinition.Id).In(subQuery)
        .Future();

    var stringValuesQuery = Session.QueryOver<StringValuesTerm>()
        .WithSubquery.WhereProperty(c => c.SearchDefinition.Id).In(subQuery)
        .Future();

    var timespanValuesQuery = Session.QueryOver<TimeSpanValuesTerm>()
        .WithSubquery.WhereProperty(c => c.SearchDefinition.Id).In(subQuery)
        .Future();


    if (searchDefinitionsWithTerms.Count() == 0)
    {
        return searchDefinitionsWithTerms;

    }

    /*if the searchDefinitions collection isn't empty- make sure all collections are initialized.
     * 
     * since our fetching strategies are all 'SubSelect' (see SearchDefinitionMappingOverride, SearchDefinitionTermsMappingOverride),
     * all we need to do is inialize ONE collection of each type (intValuesTerms, string values Terms etc..), and then automatically all other collections of the same type will also be initialized.
     * (look at the generated sql query for further info).
     * for example: if we have 5 searchDefinitions, each with 1 Term of type 'IntValuesTerm', it's enough to initialize just one of those collections, and then all others of the same type will be initialized as well.
     */


    //need to initalize each type of collection (int, string, timespan) once, in order for all the collections of that type to initialize
    IntValuesTerm intTerm = (IntValuesTerm) searchDefinitionsWithTerms.SelectMany(p => p.Terms).FirstOrDefault(c => c is IntValuesTerm);
    if (intTerm != null )
    {
        NHibernateUtil.Initialize(intTerm.IntValues);
    }

    StringValuesTerm stringTerm = (StringValuesTerm)searchDefinitionsWithTerms.SelectMany(p => p.Terms).FirstOrDefault(c => c is StringValuesTerm);
    if (stringTerm != null)
    {
        NHibernateUtil.Initialize(stringTerm.StringValues);
    }

    TimeSpanValuesTerm timespanTerm = (TimeSpanValuesTerm)searchDefinitionsWithTerms.SelectMany(p => p.Terms).FirstOrDefault(c => c is TimeSpanValuesTerm);
    if (timespanTerm != null)
    {
        NHibernateUtil.Initialize(timespanTerm.TimeSpanValues);
    }

    return searchDefinitionsWithTerms; 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!