QueryOver by join and add conditions by Independent if - nhibernate

I have a QueryOver by JoinQueryOver In Nhibernate 3.1
The Person class has a association by Identity class (one-to-one)
Code is a field of Person class and FirstName is a field of Identity class.
var q = SessionInstance.QueryOver<Person>()
.Where(p => p.Code.IsLike(code,MatchMode.Start))
.Full.JoinQueryOver(p => p.Identity);
if (!String.IsNullOrEmpty(firstName))
q = q.Where(i => i.FirstName.IsLike(firstName, MatchMode.Anywhere));
return q.List<Person>();
that result is correct but, there is a problem. The search does not include items by null value for Code field in Person class. I corrected to following query.
var q = SessionInstance.QueryOver<Person>()
.Full.JoinQueryOver(p => p.Identity);
if (!String.IsNullOrEmpty(Code))
q = q.Where(i => i.Person.Code.IsLike(code, MatchMode.Start));
if (!String.IsNullOrEmpty(firstName))
q = q.Where(i => i.FirstName.IsLike(firstName, MatchMode.Anywhere));
return q.List<Person>();
Now i have a runtime error by this message:
could not resolve property: Identity.Code of: MyNameSpace.Domain.Entities.Identity
in a query by join between two class, How can add two condition(where) by if.
(if parameter != null)

Identity identityAlias = null;
var q = SessionInstance.QueryOver<Person>()
.Full.JoinAlias(p => p.Identity, () => identityAlias);
if (!String.IsNullOrEmpty(code))
q.Where(p => p.Code.IsLike(code, MatchMode.Start));
if (!String.IsNullOrEmpty(firstName))
q.Where(() => identityAlias.FirstName.IsLike(firstName, MatchMode.Anywhere));
or
var q = SessionInstance.QueryOver<Person>();
if (!String.IsNullOrEmpty(code))
q.Where(p => p.Code.IsLike(code, MatchMode.Start));
if (!String.IsNullOrEmpty(firstName))
q.Full.JoinQueryOver(p => p.Identity)
.Where(i => i.FirstName.IsLike(firstName, MatchMode.Anywhere));

Related

Multiple Conditions in Nhibernate Left Join

Please need some help converting this sql query to nhibernate
select a.ID, count(b.ID)
from appusers a
left join weeklytasks b on a.ID = b.TaskOwner and b.taskstatus = 1
group by a.ID
It's difficult to answer without knowing your entities, mappings, used technology(ICreteria API, QueryOver, Linq).
But I can suggest this solution using QueryOver:
AppUser ownerAlias = null;
WeeklyTask taskAlias = null;
var result = Session.QueryOver(() => taskAlias)
.JoinAlias(x => x.TaskOwner,
() => ownerAlias,
NHibernate.SqlCommand.JoinType.RightOuterJoin,
Restrictions.Where(() => taskAlias.Status == 1))
.SelectList(list => list
.SelectGroup(x => ownerAlias.Id)
.SelectCount(x => x.Id))
.List<object[]>();
or this:
var result = Session.QueryOver<WeeklyTask>()
.Where(x => x.Status == 1)
.Right.JoinQueryOver(x => x.TaskOwner)
.SelectList(list => list
.SelectGroup(x => x.TaskOwner.Id)
.SelectCount(x => x.Id))
.List<object[]>();
Please notice that in this approach your WeeklyTask entity must contains mapped reference to AppUser entity.

How to do more than one level projection in query over?

I tired this
respondentSanctionSubquery = respondentSanctionSubquery.Select(x => x.Respondent.Incident.Id);
but i got this exception :
i have 3 entities not 2 entities :
class Respondent
{
public IncidentObj{get;set;}
}
class Incident
{
public int Id{get;set;}
}
class RespondentSanction
{
public Respondent RespondentObj{get;set;}
}
You have to join other entities also to the main query (as follows),
X x = null;
Respondent respondent = null;
Incident incident = null;
respondentSanctionSubquery = respondentSanctionSubquery
.JoinQueryOver(() => x.Respondent , () => respondent)
.JoinQueryOver(() => respondent.Incident , () => incident )
.Select(r => incident.Id);
or else you might want to go for subqueries,
X x = null;
Respondent respondent = null;
Incident incident = null;
var subQuery = (QueryOver<Respondent>)session.QueryOver<Respondent>(() => respondent)
.JoinQueryOver(() => respondent.Incident , () => incident )
.Where(() => respondent.Id == x.Respondent.Id)
.Select(r => incident.Id);
var query = session.QueryOver(() => x)
.SelectList(l => l.SelectSubQuery(subQuery));
You have to do a JOIN in order to do a projection like that:
respondentSanctionSubquery =
respondentSanctionSubquery
.JoinQueryOver(x => x.RespondentObj)
.JoinQueryOver(resp => resp.IncidentObj)
.Select(inc => inc.Id);
you should do join between the entities using Join alias
respondentSanctionSubquery =
respondentSanctionSubquery
.JoinAlias(x => x.RespondentObj)
.JoinAlias(resp => resp.IncidentObj)
.Select(inc => inc.Id);
for more information please check this URL :What is the difference between JoinQueryOver and JoinAlias?

NHibernate QueryOver association does not contain item

could someone help me to translate LINQ expression to Nhibernate QueryOver
from m in messages
where !m.Recipients.Any(rcpt => rcpt.IsDeleted && rcpt.User = user)
I tried this
var qry = Session.QueryOver<UserMessage>();
qry.Where(m => m.Recipients.Any(r => !r.IsDeleted && r.User == user));
but got
System.Exception : Unrecognised method call: System.Linq.Enumerable:Boolean Any[TSource](System.Collections.Generic.IEnumerable1[TSource], System.Func2[TSource,System.Boolean]
!m.Recipients.Any(...) translates to a "not exists" sub-query. You will need a couple of aliases to correlate the sub-query with the main query, and the sub-query will need to have a projection to make NHibernate happy.
Try something like this:
UserMessage messageAlias = null;
UserMessage recipientMessageAlias = null;
var subquery = QueryOver.Of<MessageRecipient>()
.JoinAlias(x => x.Message, () => recipientMessageAlias)
.Where(x => x.IsDeleted == true) // your criteria
.Where(x => x.User.Id == userId)
.Where(() => recipientMessageAlias.Id == messageAlias.Id) // correlated subquery
.Select(x => x.Id); // projection
var query = session.QueryOver(() => messageAlias)
.Where(Subqueries.WhereNotExists(subquery));
return query.List();
I managed to it this way:
UserMessage messageAlias = null;
var qry = Session.QueryOver<UserMessage>(() => messageAlias);
UserMessageRecipient recipientAlias = null;
var deletedbyUser = QueryOver.Of(() => recipientAlias)
.Select(x => x.Id)
.Where( () => recipientAlias.Message.Id == messageAlias.Id
&& (recipientAlias.Recipient == query.User && recipientAlias.IsDeleted))
.DetachedCriteria;
qry.Where(Subqueries.NotExists(deletedbyUser));
Try to use the Linq version with session.Query<> instead of QueryOver
var qry = Session.Query<UserMessage>();
qry.Where(m => m.Recipients.Any(r => !r.IsDeleted && r.User == user));

Linq to NHibernate: Select multiple sums at once

Is there a way to select multiple sums at once using Linq to NHibernate?
Now I have
int? wordCount = (from translation in session.Query<TmTranslation>()
where translation.SatisfiesCondition
select translation.TranslationUnit)
.Sum(x => (int?)(x.WordCount + x.NumberCount)) ?? 0;
int? tagCount = (from translation in session.Query<TmTranslation>()
where translation.SatisfiesCondition
select translation.TranslationUnit)
.Sum(x => (int?)(x.TagCount)) ?? 0;
int? characterCount = (from translation in session.Query<TmTranslation>()
where translation.SatisfiesCondition
select translation.TranslationUnit)
.Sum(x => (int?)(x.CharacterCount)) ?? 0;
which generates three different SQL queries. In SQL I can grab them all three at once, but is there a way to do this in Linq to NHibernate?
Thank you.
this should help get you started with QueryOver way...
ResultDTO dtoAlias = null; //placeholder alias variable
var dto = session.OueryOver<TmTranslation>()
.Where(x => x.SatisfiesCondition)
//Change this to the actual type of Translation property
.JoinQueryOver<Translation>(x => x.Translation)
.SelectList(list => list
//we can sum these columns individually to keep query simple,...add them together later
.SelectSum(x => x.WordCount).WithAlias(() => dtoAlias.WordCountTotal)
.SelectSum(x => x.NumberCount).WithAlias(() => dtoAlias.NumberCountTotal)
//add more select sums to the select list
)
.TransformUsing(Transformers.AliasToBean<ResultDTO>())
.SingleOrDefault<ResultDTO>();
Having multiple aggregate functions within a Select() call works and results in a single SQL command sent to the database. For example:
var result = session.Query<TmAssignment>()
.Select(a => new
{
Words = session.Query<TmTranslation>().Where(s => s.Assignment == a).Sum(u => (int?) u.WordCount) ?? 0,
Others = session.Query<TmTranslation>().Where(s => s.Assignment == a).Sum(u => (int?)(u.TagCount + u.NumberCount)) ?? 0,
}).ToList();
A potentially simpler solution I use is to do an artificial GroupBy then project to an anonymous object:
eg.
session.Query<TmTranslation>()
.Where(o => o.SatisfiesCondition)
.Select(o => o.TranslationUnit)
.GroupBy(o => 1)
.Select(o => new
{
WordCount = o.Sum(x => (int?)(x.WordCount + x.NumberCount)) ?? 0,
TagCount = o.Sum(x => (int?)(x.TagCount)) ?? 0,
CharacterCount = o.Sum(x => (int?)(x.CharacterCount)) ?? 0
})
.Single();
This also produces just a single SQL statement and reduces the duplication nicely.

NHibernate QueryOver how to join on non declared relationship

How to do the following join to return Users who have access to a Company given a company id.
The problem is there is no explicit relationship using a User object between UserAccess and User they simply join on the string property Username:
User(Username, Name)
UserAccess(Username, Company)
Company(Id)
Session.QueryOver<Company>()
.Where(c => c.Id == companyId)
.JoinQueryOver<UserCompanyAccess>(u => u.UserAccessList)
.JoinQueryOver<User>(u => **Nope no property, just a string**
could be done with a subquery
var subquery = QueryOver.Of<Company>()
.Where(c => c.Id == companyId)
.JoinQueryOver<UserCompanyAccess>(u => u.UserAccessList)
.Select(uca => uca.UserName);
var users = session.QueryOver<User>()
.WithSubquery.WhereProperty(u => u.Name).In(subquery)
.List();
As of 5.1.0, it is possible to make hibernate generate an actual sql join on an undeclared (unmapped) relationship. E.g. all orders sorted by customer's spending:
var criteria = _session
.CreateCriteria<Order>("order");
criteria
.CreateEntityAlias(
"customer",
Restrictions.EqProperty("order.customerId", "customer._id"),
JoinType.LeftOuterJoin,
typeof(Customer).FullName)
.AddOrder(new Order("customer._lifetimeSpending", ascending:false));
return criteria.List<Order>();
Also possible with QueryOver (sample from NHibernate docs):
Cat cat = null;
Cat joinedCat = null;
var uniquelyNamedCats = sess.QueryOver<Cat>(() => cat)
.JoinEntityAlias(
() => joinedCat,
() => cat.Name == joinedCat.Name && cat.Id != joinedCat.Id,
JoinType.LeftOuterJoin)
.Where(() => joinedCat.Id == null)
.List();