I have tag class which have relation many-to-many with article class, The problem is I want to make a projection which represent in tag view model class so the column result should be like this
Id|Name|CreatedBy|CreatedDate|LastModifiedBy|LastModifiedDate|ArticlesCount
SQL query should be like this:
SELECT t.*, COUNT(at.intTag) as ArticlesCount
FROM dbo.TAG t
LEFT OUTER JOIN dbo.ARTICLE_TAG at ON t.intID = at.intTag
LEFT OUTER JOIN dbo.ARTICLE a ON at.intID = a.intID
GROUP BY t.intID, t.vcName, t.intWeight, t.vcCreatedBy, t.dtCreated, t.vcLastMod, t.dtLastMod, t.btActive
but it said
NHibernate.Exceptions.GenericADOException was caught
HResult=-2146232832
Message=could not execute query [ SELECT this_.intID as y0_, this_.vcName as y1_, this_.vcCreatedBy as y2_, this_.dtCreated as y3_, this_.vcLastMod as y4_, this_.dtLastMod as y5_, count(this_.intID) as y6_ FROM TB_TAG this_ WHERE this_.btActive = @p0 ]
Name:cp0 - Value:True
this is my Tag class:
public class Tag {
public virtual string Name { get; set; }
public virtual int Weight { get; set; }
public virtual IList<Article> Articles { get; set; }
public virtual string CreatedBy { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual string LastModifiedBy { get; set; }
public virtual DateTime LastModifiedDate { get; set; }
public virtual bool IsActive { get; set; }
}
this is mapping class
internal sealed class TagMap : ClassMap<Tag>
{
public TagMap()
{
Table("TB_TAG");
Id(f => f.Id).Column("intID").GeneratedBy.Native();
Map(f => f.Name).Column("vcName").Not.Nullable();
Map(f => f.Weight).Column("intWeight").Not.Nullable();
Map(f => f.IsActive).Column("btActive");
Map(f => f.CreatedBy).Column("vcCreatedBy").Not.Update();
Map(f => f.CreatedDate).Column("dtCreated").Not.Update();
Map(f => f.LastModifiedBy).Column("vcLastMod");
Version(f => f.LastModifiedDate).Column("dtLastMod");
HasManyToMany(f => f.Articles).Table("S_ARTICLE_TAG")
.ParentKeyColumn("intTag").ChildKeyColumn("intID")
.Inverse();
}
}
this is ViewModel class:
public class TagView
{
public int Id { get; set; }
public string Name { get; set; }
public int ArticlesCount { get; set; }
public virtual string CreatedBy { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual string LastModifiedBy { get; set; }
public virtual DateTime LastModifiedDate { get; set; }
public virtual bool IsActive { get; set; }
}
here is my code to make a projection :
Tag t = null;
tags = _session.QueryOver(() => t)
.Select(Projections.Id().As("Id"),
Projections.Property(() => t.Name).As("Name"),
Projections.Property(() => t.CreatedBy).As("CreatedBy"),
Projections.Property(() => t.CreatedDate).As("CreatedDate"),
Projections.Property(() => t.LastModifiedBy).As("LastModifiedBy"),
Projections.Property(() => t.LastModifiedDate).As("LastModifiedDate"),
Projections.Count(() => t.Articles).As("ArticlesCount"))
.TransformUsing(Transformers.AliasToBean<TagView>())
.List<TagView>();
This is my first time using projections and I don't have any clue how to make it work. Did I have miss something here?
The error you are getting tells that the SQL generated by NHibernate for the projections cannot be executed in its current form. The query being
SELECT this_.intid AS y0_,
this_.vcname AS y1_,
this_.vccreatedby AS y2_,
this_.dtcreated AS y3_,
this_.vclastmod AS y4_,
this_.dtlastmod AS y5_,
Count(this_.intid) AS y6_
FROM tb_tag this_
WHERE this_.btactive = @p0
This is simply due to the fact that count is a aggregation needs an aggregation function.
You could mark the collection of Articles as lazy and extra and fetch the Article.Count value without loading the entire collection if that is why you are projecting each column for. There are quite a few valid articles which can guide you to mark a collection as extra lazy .
After read NHIibernate API and the answer on this link , finally i found a way to make it work.
Here is my final code:
Tag t= null;
TagView tv = null;
tags = _session.QueryOver(() => t)
.Left.JoinQueryOver(() => t.Articles, () => a)
.SelectList(list => list
.SelectGroup(() => t.Id).WithAlias(() => tv.Id)
.SelectGroup(() => t.Name).WithAlias(() => tv.Name)
.SelectGroup(() => t.CreatedBy).WithAlias(() => tv.CreatedBy)
.SelectGroup(() => t.CreatedDate).WithAlias(() => tv.CreatedDate)
.SelectGroup(() => t.LastModifiedBy).WithAlias(() => tv.LastModifiedBy)
.SelectGroup(() => t.LastModifiedDate).WithAlias(() => tv.LastModifiedDate)
.SelectCount(() => t.Articles).WithAlias(() => tv.ArticlesCount))
.TransformUsing(Transformers.AliasToBean<TagView>())
.List<TagView>();
I need to use .SelectList instead of .Select to projecting a list, also to make nhibernate succesfully counting the articles I need to join it with its related table, to speed up my query also in mapping class initialize tag articles as ExtraLazyLoad property. Hoping I also help someone out there who is facing same problem.
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.