Why doesn't ICriteria pass variable value to the withClause? - nhibernate

I'm trying to restrict a left outer join with a simple restriction but it fails with an sql exception.
System.Data.SqlClient.SqlException: Must declare the scalar variable "#p1".
My ICriteria:
var r = session.CreateCriteria<Parent>("p")
.CreateCriteria("p.Children", "c", NHibernate.SqlCommand.JoinType.LeftOuterJoin, Restrictions.Eq("c.Name", "John Doe"))
.List();
The desired SQL:
SELECT * FROM Parents p
LEFT OUTER JOIN Children c ON c.ParentID = p.ID AND c.Name = 'John Doe'
Do I have to add the variable values in any way? The SQL generated by NHibernate is correct but the variable just isn't sent to the server.

I think that you may have found a bug in NHibernate ICriteria where you join with LeftOuterJoin on one collection but entity has two or more collections. In this case it will generate joins with 'and' on both collections with two parameters, but only supply one. And database will throw:
Insufficient parameters supplied to the command
It might be a good idea to open a bug. In the mean time, this is supported with HQL:
var query = session.CreateQuery(
"select p from Parent p left outer join p.Children as c with c.Name = :name");
query.SetString("name", "John Doe");
var parents = query.List<Parent>();

Related

PostgreSQL, how to resolve multiple row errors returned by a subquery used as expression

I'm trying to output rows consisting of a value and a list of names. This is my query:
Update person set institution_v2 = (select dv.entity_id
from dictionary_v2 dv
left join dictionary_entry_v2 dev on dev.dictionary_id = dv.id
left join person p on p.name = dev.entry_value
JOIN journal_person_relation jpr on jpr.person_id = p.person_id
JOIN journal j on jpr.journal_id = j.journal_id)
But it fails with:
SQL Error [21000]: ERROR: more than one row returned by a subquery used as an expression
how can i solve this problem?
Presumably, you intend a correlated subquery. So, don't re-use person in the subuqery:
update person p
set institution_v2 = (select dv.entity_id
from dictionary_v2 dv join
dictionary_entry_v2 dev
on dev.dictionary_id = dv.id
where p.name = dev.entry_value
);
Note: This could still return duplicates. It is possible that a single value is not appropriate for the column -- perhaps you want an array -- or if an arbitrary matching value works, use limit 1.
I don't think the journal tables are adding anything to the logic.

Need help to Convert SQL to LINQ

i need help, i need to convert the following query from SQL to LINQ.
and use it in my mvc view
select b.ID from LibraryTable a
left join User b on a.UserNumber=b.UserNumber
From msdn: Left Outer Joins
var query = from t in LibraryTable
join u in User on t.UserNumber equals u.UserNumber into tu
from d in tu.DefaultIfEmpty()
select new { Id = u == null ? 0 : u.ID };
However, you say you want a left join, but only select something from the right table. This example will just return 0 for anything in LibraryTable that does not have a User record. You may want to consider also selecting something from the left table. To do that, add a new property in the anonymous type in the select.

Using an INNER JOIN to join two tables in HQL

I have an SQL query that I need to convert to an HQL query.
I have a class Item that contains a set of Components. The SQL table for Item is DBO.W_ITEM and the table for Component is DBO.W_COMPONENT.
In SQL, I've had no trouble doing this like so...
SELECT
item.noun,
comp.type
FROM
DBO.W_ITEM item
INNER JOIN DBO.W_COMPONENT comp ON item.id = comp.id
However, I can't get this to work in HQL.
I've tried it like this...
SELECT
item.noun,
comp.type
FROM
InventoryItemInv item
INNER JOIN item.components comp ON item.id = comp.id
but the HQL doesn't seem to know what to do with the ON - and says it's an unexpected token. According to all the literature, HQL supports the ON keyword.
Any suggestions?
Thanks in advance!
You don't need to use the ON clause to define the binding column, Hibernate will infer it from the relationship defined in the model, following HQL query should work for you
SELECT item.noun, comp.type
FROM InventoryItemInv item
INNER JOIN item.components comp

NHibernate query fails with "the multi-part identifier could not be bound" on an aggregate query

I'm trying to understand why this simple query is generating the wrong SQL on NHibernate 3.3:
var query = session.CreateQuery(#"select count(*) as C
from Parent p
inner join fetch p.Child c
where c.Field = 'someValue'");
When I execute this query the generated SQL does NOT include a reference to the Child table, which causes the dreaded "the multi-part identifier _child.FIELD could not be bound" exception.
Anyone has an idea on why this problem and how to solve it?
Thanks!
Assign a different alias to count(*), probably nhibernate is getting confused since you're using c and C as aliases.
For instance, you could set your query like this
var query = session.CreateQuery(#"select count(*) as co
from Parent p
inner join fetch p.Child c
where c.Field = 'someValue'");
Just for reference, if someone else gets burned by this.
It seems the internals of NHibernate are filtering out join when generating the query.
So, the only solution we found was to rephrase the query this way:
select count(*) as C
from Parent p
where p.Child.Field = 'someValue'
This way, NHibernate is going to generate the join syntax (using cross join operators and where clauses).

SQL Server/T-SQL via JSP: "The multi-part identifier XX.YY could not be bound"

I'm getting the error:
the multi-part identifier "IC.industry" could not be bound
when making this SQL query from a JSP page via JDBC:
select C.company, C.shname, C.fullname, count(d_to_c.designer)
from companies C
left join ind_to_c IC on C.company = IC.company
left join d_to_c on C.company= d_to_c.company
where IC.industry = ?
group by C.company, C.shname, C.fullname
order by C.shname
and I'm trying to run it as a prepared statement, where I'm setting the parameter via (for example) stmt.setObject(1, 7) prior to running stmt.executeQuery().
Now, what's weird is: If I execute this with the ? and set the parameter as I just mentioned, I get the "could not be bound" error. If, however, I just change the query and hardcode the number 7 into the text of the query, it works!
So it has something to do with binding that parameter.
But I can't seem to figure out what.
Anybody?
UPDATE: Per request, the table definition for ind_to_c:
industry - int(11)
company - int(11)
(it's just a table that defines the m2m relationship between industries and companies)
UPDATE 2: Also per request, the full JSP code. I had to pull this out of a call to an abstraction of the database connection (which we use to store prepared statements, etc.
// conn has been initialized as the db connection object.
int parent_id = 7;
PreparedStatement ps = conn.prepareStatement("select C.company, C.shname, C.fullname, count(d_to_c.designer) from companies C left join ind_to_c IC on C.company = IC.company left join d_to_c on C.company = d_to_c.company where IC.industry = ? group by C.company, C.shname, C.fullname order by C.shname");
ps.setObject(1, parent_id);
ResultSet rs = null;
rs = ps.executeQuery();
What's the data type for industry? Does it make a difference if you use the type specific bind methods like stmt.setInt(1,7) instead?
edit: also, not related to the question, but you should probably remove C.cid from the SELECT. Some variants of T-SQL will infer that you want to group by that column since it is not the subject of an aggregation function, even though you don't specifiy it in the GROUP BY clause.
Back on topic, can you post the table definition for ind_2_c? The nature of the error would seem to indicate that it has no column called industry.
Have you tried passing a named parameter (i.e: #industry) instead of a question mark?
Maybe I am just thinking to simple here because i do not know JSP to well but would dit not just work:
int parent_id = 7;
PreparedStatement ps = conn.prepareStatement("select C.company, C.shname, C.fullname, count(d_to_c.designer) from companies C left join ind_to_c IC on C.company = IC.company left join d_to_c on C.company = d_to_c.company where IC.industry = ? group by C.company, C.shname, C.fullname order by C.shname");
ps.setInt(1, parent_id );
ResultSet rs = null;
rs = ps.executeQuery();
I see from your comments that you can only use SetObject.
But why do you pass an object array instead of a single object? (if I read Java correctly)
I upgraded to the newer v. 2.0 of the MS-SQL JDBC driver, and magically it worked.