Selecting a SubQuery from a DetachedCriteria - fluent-nhibernate

I have the following criteria and detachedCriteria.
var criteria = Session.CreateCriteria<ItemAnalysis>("ia");
criteria.CreateAlias("ia.ItemInstance", "ii");
criteria.CreateAlias("ii.ScoreAdministration", "sa");
criteria.Add(Restrictions.Eq("ii.ItemId", itemId));
var status = DetachedCriteria.For<ItemAnalysis>("ia_")
.CreateAlias("ia_.ItemInstance", "ii_")
.CreateAlias("ii_.ScoreAdministration", "sa_")
.Add(Restrictions.Eq("ii_.ItemId", itemId))
.SetProjection(
Projections.SqlProjection
(
"ia_.CTTItemStatId, RANK() OVER(Partition BY
sa_.ExamSeriesCode ORDER BY ia_.StatDate DESC) AS RowNm",
new string[] { "CTTItemStatId", "RowNm" },
new IType[] { NHibernate.NHibernateUtil.Int32,
NHibernate.NHibernateUtil.Int32 }
)
);
I need a way to get a projection or second subquery from the detached query that has just that property and adds a restriction of RowNm=1. I looked at DetachedCriteria.CreateCriteria but that requires an Association Path. I haven't found any similar examples. I did try
// what parameters should I be using here??
var subQuery = status.CreateCriteria(?, ?) // expects an association path and an alias
.Add(Restrictions.Eq("RowNm", 1))
.SetProjection(
Projections.Property("CTTItemStatId")
);
criteria = criteria.Add(Subqueries.PropertyEq("CTTItemStatId", subQuery));

Related

Dynamic column search in multiple tables with gorm golang

My scenario is i have a grid with search option where user can select the column and can do the search, the grid data is coming from various tables. I have attached a sample screen of grid.
User Screen
So i'm trying to create a dynamic query for search but the problem is i can able to search only in main table (schema.Robot) not in Preload tables. whenever i trying to search data data from Preload tables let say from RobotModel table that time getting below error
pq: missing FROM-clause entry for table "robot_models"
Here is my go code
func (r *RobotsRepository) GetRobotsSummary(listParams viewmodel.ListParams, companyID uint) ([]*schema.Robot, int, error) {
mrobots := []*schema.Robot{}
var count int
var order string
if listParams.SortColumn == "" {
listParams.SortColumn = "id"
listParams.SortOrder = 1
} else {
listParams.SortColumn = util.Underscore(listParams.SortColumn)
}
if listParams.SortOrder == 0 {
order = "ASC"
} else {
order = "DESC"
}
var searchQuery string
if listParams.SearchText != "" {
switch listParams.SearchColumn {
case "Robot":
listParams.SearchColumn = "name"
case "Model":
listParams.SearchColumn = "robot_models.name"
}
searchQuery = listParams.SearchColumn +" LIKE '%"+ listParams.SearchText +"%' and Company_ID = " + fmt.Sprint(companyID)
}else{
searchQuery = "Company_ID = " + fmt.Sprint(companyID)
}
orderBy := fmt.Sprintf("%s %s", listParams.SortColumn, order)
err := r.Conn.
Preload("RobotModel", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Name")
}).
Preload("Task", func(db *gorm.DB) *gorm.DB {
return db.Where("Task_Status in ('In-Progress','Pending')").Select("ID, Task_Status")
}).
Preload("CreatedUser", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Display_Name")
}).
Preload("UpdatedUser", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Display_Name")
}).
Where(searchQuery).
Order(orderBy).
Offset(listParams.PageSize * (listParams.PageNo - 1)).
Limit(listParams.PageSize).
Find(&mrobots).Error
r.Conn.Model(&schema.Robot{}).Where(searchQuery).Count(&count)
return mrobots, count, err
}
In searchQuery variable i'm storing my dynamic query.
My question is how can i search data for preload table columns
Here is the sql query which i'm trying to achieve using gorm
SELECT robots.id,robots.name,robot_models.name as
model_name,count(tasks.task_status) as task_on_hand,
robots.updated_at,users.user_name as updated_by
FROM rfm.robots as robots
left join rfm.tasks as tasks on tasks.robot_id = robots.id and
tasks.task_status in ('In-Progress','Pending')
left join rfm.robot_models as robot_models on robot_models.id =
robots.robot_model_id
left join rfm.users as users on users.id = robots.updated_by
WHERE robot_models.name::varchar like '%RNR%' and robots.deleted_at is null
GROUP BY robots.id,robot_models.name,users.user_name
ORDER BY task_on_hand DESC LIMIT 2 OFFSET 0
and sorry for bad English!
Even though you are preloading, you are still required to explicitly use joins when filtering and ordering on columns on other tables. Preloading is used to eagerly load the data to map into your models, not to join tables.
Chain on something like this:
.Joins("LEFT JOIN rfm.robot_models AS robot_models ON robot_models.id = robots.robot_model_id")
I'm not positive if you can use the AS keyword using this technique, but if not, it should be easy enough to adjust your query accordingly.

NHibernate Linq Expression dynamic projection

How can i dynamically change the selected columns in the generated sql query when using a linq expression?
Its a new session for each time the query is executed.
Even when I set the MapExp as null after first creation an then changing the bool value to false, it still generates the column in the sql query.
The code runs in a wpf application.
System.Linq.Expressions.Expression<Func<Entity, Model>> MapExp = x => new Model
{
Id=xId,
Count= LoadFormulaField ? x.Count: null,
...
};
var result = session.Query<Entity>().Select(MapExp))
Your problem seems to be the ternary-conditional as part of the expression which is causing the "Count" column to always be queried.
One option to avoid this could be:
var query = session.Query<Entity>();
IQueryable<Model> result = null;
if (LoadFormulaField)
{
result = query.Select(x => new Model
{
Id = x.Id,
Count = x.Count,
});
}
else
{
result = query.Select(x => new Model
{
Id = x.Id,
});
}
Which would get a little less ugly if you separate in a couple of methods I think.

How to map ONE-TO-MANY native query result into a POJO class using #SqlResultSetMapping

Im working in a backend API using Java and MySql, and I'm trying to use #SqlResultSetMapping in JPA 2.1 for mapping a ONE-TO-MANY native query result into a POJO class, this is the native query:
#NamedNativeQuery(name = "User.getAll”, query = "SELECT DISTINCT t1.ID, t1.RELIGION_ID t1.gender,t1.NAME,t1.CITY_ID , t2.question_id, t2.answer_id FROM user_table t1 inner join user_answer_table t2 on t1.ID = t2.User_ID“,resultSetMapping="userMapping")
And, here is my result SQL mapping:
#SqlResultSetMapping(
name = "userMapping",
classes = {
#ConstructorResult(
targetClass = MiniUser.class,
columns = {
#ColumnResult(name = "id"),
#ColumnResult(name = "religion_id"),
#ColumnResult(name = "gender"),
#ColumnResult(name = "answers"),
#ColumnResult(name = "name"),
#ColumnResult(name = "city_id")
}
),
#ConstructorResult(
targetClass = MiniUserAnswer.class,
columns = {
#ColumnResult(name = "question_id"),
#ColumnResult(name = "answer_id")
}
)
})
And, here is the implementation of the POJO classes: (I just removed the constructor and the getters/setter)
MiniUser class
public class MiniUser {
String id;
String religionId;
Gender gender;
List<MiniUserAnswer> answers;
String name;
String city_id;
}
and the MiniUserAnswer class
public class MiniUserAnswer {
String questionId;
String answerId;
}
My goal is to execute this Query and return a list of MiniUser, and in each MiniUser: a list of his “answers", which is a list of MiniUserAnswer.
after running this code, I got this error:
The column result [answers] was not found in the results of the query.
I know why, it's because there is no “answers" field in the query select statement.
So, how can I accomplish something like this, considering the performance? This answers list may reach 100.
I really appreciate your help, Thanks in advance!
The query "SELECT DISTINCT t1.ID, t1.RELIGION_ID t1.gender, t1.NAME, t1.CITY_ID, t2.question_id, t2.answer_id" does not return a parameter called answers.
To obtain the result you are looking for I would use:
Option 1 (Criteria Builder)
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserTableEntity> cq = cb.createQuery(UserTableEntity.class);
Root<UserTableEntity> rootUserTable = cq.from(UserTableEntity.class);
Join<UserTableEntity,UserAnswerTableEntity> joinAnswerTable = rootUserTable.join(rootUserTable_.id) // if the relationship is defined as lazy, use "fetch" instead of "join"
//cq.where() NO WHERE CLAUSE
cq.select(rootUserTable)
entityManager.createQuery(cq).getResultList();
Option 2 (Named query, not native)
#NamedQuery(name = "User.getAll”, query = "SELECT t1 FROM UserTableEntityt1 join fetch t1.answers)
Option 3 (Entity subgraph, new in JPA 2.1)
In User Entity class:
#NamedEntityGraphs({
#NamedEntityGraph(name = "graph.User.Answers", attributeNodes = #NamedAttributeNode("answers"))
})
In DAO set hints in the entity manager:
EntityGraph graph = this.em.getEntityGraph("graph.User.Answers");
Map hints = new HashMap();
hints.put("javax.persistence.fetchgraph", graph);

NHibernate Criteria API help needed please

I'm trying to create a criteria query that grabs "RejectedRecords" by useruploaded that are not flagged as being deleted or the Facility in the RejectedRecord is in a list of facilities that a user is assigned to (user.UserFacilities). I have the first part working fine (By User and Not Deleted) but I'm not sure how to add the OR clause to take records that are in the collection of user-facilities. In SQL it would look like:
SELECT *
FROM RejectedRecords
WHERE (UserUploaded = 1 AND IsDeleted = 0)
OR FacilityId IN (SELECT FacilityId FROM UserFacility WHERE UserId = 1)
Here's my attempt in C# (Not sure how to perform the subquery):
public IList<RejectedRecord> GetRejectedRecordsByUser(User u)
{
return base._session.CreateCriteria(typeof(RejectedRecord))
.Add(
(
Expression.Eq(RejectedRecord.MappingNames.UserUploaded, u)
&& Expression.Eq(RejectedRecord.MappingNames.IsDeleted, false)
)
)
.List<RejectedRecord>();
}
The Key is to use Disjunction and Conjunction combined with a Subquery.
var facilityIdQuery = DetachedCriteria.For<UserFacility>()
.Add(Expression.Eq("User.Id", u))
.SetProjection(Projections.Property("Facility.Id"));
var results = session.CreateCriteria<RejectedRecords>()
.Add(
Restrictions.Disjunction()
.Add(
Restrictions.And(
Restrictions.Eq(RejectedRecord.MappingNames.UserUploaded, u),
Restrictions.Eq(RejectedRecord.MappingNames.IsDeleted, false)
)
)
.Add(Subqueries.PropertyIn("FacilityId",facilityIdQuery))
).List();

NHibernate 3.0 - Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."

We are trying to upgrade to NHibernate 3.0 and now i am having problem with the following Linq query. It returns "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS." error.
This is the linq query in the controller.
var list = (from item in ItemTasks.FindTabbedOrDefault(tab)
select new ItemSummary
{
Id = item.Id,
LastModifyDate = item.LastModifyDate,
Tags = (from tag in item.Tags
select new TagSummary
{
ItemsCount = tag.Items.Count,
Name = tag.Name
}).ToList(),
Title = item.Title
});
and the following is the sql generated for this query
select TOP ( 1 /* #p0 */ ) item0_.Id as col_0_0_,
item0_.LastModifyDate as col_1_0_,
(select (select cast(count(* ) as INT)
from dbo.ItemsToTags items3_,
dbo.Item item4_
where tag2_.Id = items3_.Tag_id
and items3_.Item_id = item4_.Id),
tag2_.Name
from dbo.ItemsToTags tags1_,
dbo.Tag tag2_
where item0_.Id = tags1_.Item_id
and tags1_.Tag_id = tag2_.Id) as col_2_0_,
item0_.Title as col_3_0_ from dbo.Item item0_ order by item0_.ItemPostDate desc
ps:If i remove the Tags property in the linq query, it works fine.
Where is the problem in the query?
Thanks in advance.
I've got the same Generic ADO Exception error, I think it's actually the limitation of SQL server;
Is it possible somehow load object graph with projections in collections?
If I try this one:
var cats = q.Select(t => new cat()
{
NickName = t.NickName,
Legs = t.Legs.Select(l => new Leg()
{
Color = l.Color,
Size = l.Size
}).ToList()
}).ToList();
That does the same error..