NHibernate creates query with incorrect parameter list - sql

I'm getting a GenericADOException with the message:
could not execute query
related to the following query, being generated by NHibernate:
select aggregated0_.Id as col_0_0_
, aggregated0_.Name as col_1_0_
, aggregated0_.Event as col_2_0_
, cast(count(distinct aggregated0_.Code) as INT) as col_3_0_
from Events aggregated0_
where
aggregated0_.RelatedId=#p0
and aggregated0_.S_Id=#p1
and aggregated0_.HappenedAt >=#p2
group by
aggregated0_.Id
, aggregated0_.Name
, aggregated0_.Event
Name:p1 - Value:97c58b27-460d-4fae-8185-b215e2d11882
Name:p2 - Value:4d3b7583-4b46-46e2-8bcd-169b26fd3541
Name:p3 - Value:7/25/2017 11:00:00 PM
As you can see, the parameter list is, incorrectly, using p1, p2 and p3. However, the query needs p0, p1 and p2.
Why is NH creating an incorrect parameter list?
Mapping:
public AggregatedEventMap()
{
SchemaAction.None();
Table("Events");
ReadOnly();
Not.LazyLoad();
Id(e => e.E_Id).GeneratedBy.Assigned();
Map(m => m.RelatedId);
Map(m => m.S_Id);
Map(m => m.P_Id);
Map(m => m.Id);
Map(m => m.Name);
Map(m => m.Code);
Map(m => m.Event);
Map(m => m.EventTime).CustomType<UtcDateTimeType>();
Map(m => m.HappenedAt).CustomType<UtcDateTimeType>();
}
Query is built as follows:
var query =
Session
.Query<AggregatedEvent>()
.Where(e => e.RelatedId == parameters.RelatedId);
if (parameters.S_Id.HasValue)
{
query =
query.Where(e => e.S_Id == parameters.S_Id.Value);
}
if (parameters.P_Id.HasValue)
{
query = query.Where(e => e.P_Id == parameters.P_Id.Value);
}
if (parameters.Id.HasValue)
{
query = query.Where(e => e.Id == parameters.Id.Value);
}
if (parameters.FromDate.HasValue)
{
query = query.Where(e => e.HappenedAt >= parameters.FromDate.Value);
}
if (parameters.ToDate.HasValue)
{
query = query.Where(e => e.HappenedAt < parameters.ToDate.Value);
}
var results =
query
.GroupBy(e => new { e.Id, e.Name, e.Event })
.Select(
g =>
new AggregatedEventResult
{
Id = g.Key.Id,
Name = g.Key.Name,
Event = g.Key.Event,
Count = g.Select(e => e.Code).Distinct().Count()
})
.ToList();
Furthermore, this doesn't happen consistently and only happens in one runtime environment. It only happens when a certain combination of parameters is used:
RelatedId, S_ID and when HappenedAt is queried for events on, or after a given date.

Related

how to write a linq with multiple join

as am a beginner,i want to get the following set of query as linq with a detailed explanation
//my sql
select COL.title as organizationtitle,CL.[title] as
cousestitle,sum(FD.feathers) as totalfeathers,sum(FD.amount) as
totalamount
from [dbo].[FeathersDonated] FD
join [dbo].[Couses] C on FD.corpid=3 and FD.[cousesid]=C.id
join [dbo].[Couses_lang] CL on FD.[cousesid]=CL.cousesid and
CL.language='en-US'
JOIN [dbo].[Organization_lang] COL on COL.orgid=2 and COL.language='en
US'
group by FD.cousesid,CL.[title],CL.[description],COL.title
i have tried the following set of code. please do help
var featherDonated = _GoUoW.FeathersDonated.FindBy(x => x.corpid ==
param.corpid)
.GroupBy(x => x.cousesid).Select(x => new { cousesid = x.Key, amount =
x.Select(a => a.amount).DefaultIfEmpty(0).Sum(), feathers = x.Select(a =>
a.feathers).DefaultIfEmpty(0).Sum() })
.Join(_GoUoW.Couses.GetAll(), feather => feather.cousesid, couse =>
couse.id, (feather, couse) => new { feather, couse })
.Join(_GoUoW.Organization_lang.FindBy(orglang => orglang.language == "en-
US"), couses => couses.couse.orgid, orgid => (param.organizationid > 0 ?
param.organizationid : orgid.orgid), (couses, orgid) => new { couses,
orgid
})
.Join(_GoUoW.Couses_lang.FindBy(couselang => couselang.language == "en-
US"),
organization => organization.orgid.orgid, couselang => couselang.cousesid,
(organization, couselang) => new { organization, couselang })
.Select(x => new
{
x.organization.couses.feather.amount,
x.organization.couses.feather.feathers,
x.couselang.title
//x.organization.orgid.title,
}).ToList();

Joining tables in NHibernate

I have a query below, How can recreate this one to join the tables that will return a list of SurveyProjectNormDTO using NHibernate? Any help please?
using (var session = OpenSession()){
var projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>()
.Where(x => x.NodeID == nodeId);
projectGroupIds.Fetch(x => x.ProjectGroupID).ToFuture();
var projectIds = session.Query<ProjectGroup>().Where(p => projectGroupIds.Contains(p.Id));
projectIds.Fetch(x => x.ProjectID).ToFuture();
var projectNormProjects = session.Query<SurveyProjectNorm>().Where(x => projectIds.Contains(x.SurveyProjectId));
projectNormProjects.Fetch(x => x.ShortLabels).ToFuture();
projectNormProjects.Fetch(x => x.ReportingNames).ToFuture();
projectNormProjects.Fetch(x => x.NormProject).ToFuture();
var response = new List<SurveyProjectNormDTO>();
projectNormProjects.ToList().ForEach(
p =>
{
response.Add(
new SurveyProjectNormDTO { Id = p.Id, ProjectName = p.NormProject.ProjectName, ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() });
});
return response;
I am not sure if these let commands will work fine but you can try this. It will do a single hit on the database fetching the properties. Test it and let us know if it works.
var queryResult = (from p in session.Query<SurveyProjectNorm>()
let projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>().Where(x => x.NodeID == nodeId).Select(x => x.Id)
let projectIds = session.Query<ProjectGroup>().Where(x => projectGroupIds.Contains(x.Id)).Select(x => x.Id)
where projectIds.Contains(p.SurveyProjectId)
select p)
.Fetch(x => x.ShortLabels)
.Fetch(x => x.ReportingNames)
.Fetch(x => x.NormProject)
.ToList();
var response = new List<SurveyProjectNormDTO>();
queryResult.ForEach(p =>
response.Add(new SurveyProjectNormDTO {
Id = p.Id,
ProjectName = p.NormProject.ProjectName,
ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() }));
return result;

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 and JoinAlias throw exception

I have query in HQL which works good:
var x =_session.CreateQuery("SELECT r FROM NHFolder f JOIN f.DocumentComputedRights r WHERE f.Id = " + rightsHolder.Id + " AND r.OrganisationalUnit.Id=" + person.Id);
var right = x.UniqueResult<NHDocumentComputedRight>();
Basically I receive NHDocumentComputedRight instance.
I've tried to implement the same query in QueryOver. I did this:
var right = _session.QueryOver<NHFolder>().JoinAlias(b => b.DocumentComputedRights, () => cp).Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp).List<NHDocumentComputedRight>();
But I get null reference exception.
How can I implement this query in QueryOver?
Update (added mappings) - NHibernate 3.2:
public class FolderMapping: ClassMapping<NHFolder>
{
public FolderMapping()
{
Table("Folders");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
Set(x => x.DocumentComputedRights, v =>
{
v.Table("DocumentComputedRightsFolder");
v.Cascade(Cascade.All | Cascade.DeleteOrphans);
v.Fetch(CollectionFetchMode.Subselect);
v.Lazy(CollectionLazy.Lazy);
}, h => h.ManyToMany());
Version(x => x.Version, map => map.Generated(VersionGeneration.Never));
}
}
public class DocumentComputedRightMapping : ClassMapping<NHDocumentComputedRight>
{
public DocumentComputedRightMapping()
{
Table("DocumentComputedRights");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
ManyToOne(x => x.OrganisationalUnit, map =>
{
map.Column("OrganisationalUnit");
map.NotNullable(false);
map.Cascade(Cascade.None);
});
}
}
public class OrganisationUnitMapping : ClassMapping<NHOrganisationalUnit>
{
public OrganisationUnitMapping()
{
Table("OrganisationalUnits");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
}
}
Thanks
AFAIK criteria/queryOver can only return the entity it was created for (NHFolder in your example) or columns which are set to entity with aliastobean. you could do a correlated subquery instead.
var subquery = QueryOver.Of<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp.Id);
var right = _session.QueryOver<NHDocumentComputedRight>()
.WithSubquery.Where(r => r.Id).Eq(subquery)
.SingleOrDefault<NHDocumentComputedRight>();
I think you have a problem with the select statement, have you tried something like this:
var right = _session.QueryOver<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(x => x.DocumentComputedRights)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.List<NHDocumentComputedRight>();
This is what is working for me so it should work in you case as well.
I would guess that the main reason behind the problem is the lack of proper overload on the Select method. In reality you would like to write it like this:
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(() => cp)
but the Expression<Func<object>> is not there. Hopefully it's going to be included in the next version.

How to take this sql query and turn it into nhibernate query

I am trying take this sql query and make it into an nhibernate HQL query. I am using nhibernate 3 and Fluent Nhibernate 1.2
SELECT dbo.Tasks.CourseId, dbo.CoursePermissions.BackgroundColor, dbo.Tasks.DueDate, dbo.Tasks.TaskName, dbo.Tasks.TaskId
FROM dbo.Courses INNER JOIN
dbo.Tasks ON dbo.Courses.CourseId = dbo.Tasks.CourseId INNER JOIN
dbo.CoursePermissions ON dbo.Courses.CourseId = dbo.CoursePermissions.CourseId
WHERE (dbo.Tasks.CourseId = 1)
I would have liked to use linq but I don't think nhibernate supports linq joins yet so I guess I am stuck with using HQL(unless someone knows a better way).
I guess I can use QueryOver or the other ways nhibernate does queries so whatever works the best. I still don't understand the difference between all the ways as if I could do everything in linq I would.
However I have no clue on how to write my query.
Thanks
Edit
I now have this(changed a bit)
Course cAlias = null;
Task tAlias = null;
CoursePermission cpAlias = null;
var result = session.QueryOver<Task>(() => tAlias)
.JoinAlias(() => tAlias.Course, () => cAlias)
.JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
.Where(Restrictions.In(Projections.Property(() => cAlias.Id), courseIds))
.And(x => x.DueDate >= startDate)
.And(x => x.DueDate <= endDate)
.Select( Projections.Property(() => cAlias.Id),
Projections.Property(() => cpAlias.BackgroundColor),
Projections.Property(() => tAlias.DueDate),
Projections.Property(() => tAlias.TaskName),
Projections.Property(() => tAlias.TaskId))
.List<object[]>();
I know want to map it to
public class TaskAppointments
{
public int Id { get; set; }
public string BackgroundColor { get; set; }
public DateTime DueDate { get; set; }
public int TaskId { get; set; }
public string TaskName { get; set; }
}
How do I do this. If this was a linq method I would do
.Select(new TaskAppointments { TaskId = Projections.Property(() => tAlias.TaskId)})
but it says it can't convert it to an int.
Edit2
This is what I came up with
Course cAlias = null;
Task tAlias = null;
CoursePermission cpAlias = null;
TaskAppointments taskAppointments = null;
List<TaskAppointments> result = session.QueryOver<Task>(() => tAlias)
.JoinAlias(() => tAlias.Course, () => cAlias)
.JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
.Where(Restrictions.In(Projections.Property(() => cAlias.Id), courseIds))
.And(x => x.DueDate >= startDate)
.And(x => x.DueDate <= endDate)
.SelectList(list =>
list.SelectGroup(x => x.TaskId).WithAlias(() => taskAppointments.TaskId)
.SelectGroup(() => cpAlias.BackgroundColor).WithAlias(() => taskAppointments.BackgroundColor)
.SelectGroup(x => x.DueDate).WithAlias(() => taskAppointments.DueDate)
.SelectGroup(x => x.TaskName).WithAlias(() => taskAppointments.TaskName)
)
.TransformUsing(Transformers.AliasToBean<TaskAppointments>())
.List<TaskAppointments>().ToList();
Without mappings I assume that you have the following relationships: Courses -> Tasks (1:n) and Courses -> CoursePermissions (1:n)
I also assumed that you do not want the complete objects but only certain properties, so I used projections.
QueryOver version:
// the aliases are required here, so that we can reference the entities properly
Courses cAlias = null;
Tasks tAlias = null;
CoursePermissions cpAlias = null;
var result = session.QueryOver<Courses>(() => cAlias)
.JoinAlias(() => cAlias.Tasks, () => tAlias)
.JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
.Where(() => cAlias.CourseId == 1)
.Select(Projections.Property(() => cAlias.CourseId),
Projections.Property(() => cpAlias.BackgroundColor),
Projections.Property(() => tAlias.DueDate),
Projections.Property(() => tAlias.TaskName),
Projections.Property(() => tAlias.TaskId))
.List<object[]>();
Edit start
If you need to do a WHERE IN clause, you can do this:
List<int> courseIdList = new List<int>() { 1, 2 };
var result = session.QueryOver<Courses>(() => cAlias)
.JoinAlias(() => cAlias.Tasks, () => tAlias)
.JoinAlias(() => cAlias.CoursePermissions, () => cpAlias)
.Where(Restrictions.In(Projections.Property(() => cAlias.CourseId), courseIdList))
.Select(...)
.List<object[]>();
Edit end
Edit 2 start
If you want to transform it into a DTO:
// AliasToBeanResultTransformer is in namespace NHibernate.Transform
// we have to use .As("...") for the transformer to find the correct property-names
var result = ...
.Select(Projections.Property(() => cAlias.CourseId).As("CourseId"),
Projections.Property(() => cpAlias.BackgroundColor).As("BackgroundColor"),
Projections.Property(() => tAlias.DueDate).As("DueDate"),
Projections.Property(() => tAlias.TaskName).As("TaskName"),
Projections.Property(() => tAlias.TaskId).As("TaskId"))
.TransformUsing(new AliasToBeanResultTransformer(typeof(TaskAppointments)))
.List<TaskAppointments>();
Edit 2 end
HQL version:
string hql = "select c.CourseId, cp.BackgroundColor, t.DueDate, t.TaskName, t.TaskId"
+ " from Courses as c inner join c.Tasks as t inner join c.CoursePermissions as cp"
+ " where c.CourseId = 1";
var result2 = session.CreateQuery(hql)
.List<object[]>();
Be aware that this will result in a cartesian product, so for each Course you will get Tasks.Count + CoursePermissions.Count rows.