FluentNhibernate Criteria LeftOuterJoin Generates duplicate rows

366 Views Asked by At

Suppose I have following classes :

public class Fund : EntityBase
{             
    public virtual string Name { get; set; }
    public virtual IList<FundDetail> FundDetails { get; set; }
    public virtual IList<FundAlias> FundAliases { get; set; } 

    public Fund()
    {
        FundDetails=new List<FundDetail>();
        FundAliases=new List<FundAlias>();    
    }
}

public class FundDetail : EntityBase
{
    public virtual string Symbol { get; set; }
    public virtual Fund Fund { get; set; }   
}

public class FundAlias : EntityBase
{
    public virtual string Symbol { get; set; }
    public virtual string Name { get; set; }
    public virtual Fund Fund { get; set; }
}

My query:

filterValue = "sometext"

var criteria = session.CreateCriteria<Fund>();
criteria.CreateAlias("FundDetails", "fd", JoinType.LeftOuterJoin);
criteria.CreateAlias("FundAliases", "fa", JoinType.LeftOuterJoin);

criteria.Add(
    Restrictions.InsensitiveLike("fd.Symbol", filterValue, MatchMode.Anywhere) ||
    Restrictions.InsensitiveLike("Name", filterValue, MatchMode.Anywhere) ||
    Restrictions.InsensitiveLike("fa.Symbol", filterValue, MatchMode.Anywhere));

criteria.SetFirstResult(0).SetMaxResults(100);
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
var list = criteria.List<Fund>();

I try to get all fund where name of fund or symbol from fundDetail or symbol from FundAlias contains filterValue that is simple string , and get 100 results.

Because LeftOuterJoin generated duplicate rows of fund , and because " criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());" is not present in generated query (SQL syntax) despite the fact that there are more than 100 results I am not getting 100 rows, I am getting different number according to how many rows was duplicated. I was taring to do it with "Projections":

criteria.SetProjection(
    Projections.Distinct(Projections.ProjectionList()
        .Add(Projections.Alias(Projections.Property("Name"), "Name"))
        .Add(Projections.Alias(Projections.Property("Id"), "Id"))
    )
);

but I didn't find how to SetProjections For a collection using CriteriaNote:

What I am doing wrong ?Is it a why to do this using Criteria?

Note:Please not that I do not want to do this using QueryOver ,I need this with Criteria.

1

There are 1 best solutions below

2
Firo On
var subquery = DetachedCriteria.For<Fund>()
    .CreateAlias("FundDetails", "fd", JoinType.LeftOuterJoin)
    .CreateAlias("FundAliases", "fa", JoinType.LeftOuterJoin)
    .Add(
        Restrictions.InsensitiveLike("fd.Symbol", filterValue, MatchMode.Anywhere) ||
        Restrictions.InsensitiveLike("Name", filterValue, MatchMode.Anywhere) ||
        Restrictions.InsensitiveLike("fa.Symbol", filterValue, MatchMode.Anywhere))
    .SetProjection(Projections.Distinct(Projections.Id()));

var funds = session.CreateCriteria<Fund>()
    .Add(Subqueries.PropertyIn(Projections.Id()).In(subquery))
    .SetFetchMode("FundDetails", FetchMode.Eager) // for example
    .OrderBy(Projections.Id())
    .SetFirstResult(0).SetMaxResults(100)
    .SetResultTransformer(Transformers.DistinctRootEntity())
    .List<Fund>();