Will hql give you compile time errors? - nhibernate

Will hql give you compile time errors like criteria query?
I remember hearing that one of the methods doesn't (besides raw SQL).

The short answer is no. Since HQL is essentially a string, you need an IDE to parse it and figure out if you're doing something wrong.

No query build in Hibernate, neither HQLs nor Critieras, will produce compile time errors. Nevertheless you can use the NamedQuery annotation to declare your static HQL queries in a static way. This will provide caching and validity checks when starting your application because hibernate's session factory will read all NamedQueries on first startup.

HQL wil not give you compile time errors, as it is only treated as a string at compile time.
What do you mean with 'like criteria query'?

Criteria queries may not give you compile time errors, something like this will error
ICriteria crit = sess.CreateCriteria(typeof(Cat));
crit.SetMaxResults("50"); /* wrong parameter type */
List cats = crit.List();
Something like this will not
IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Naem", "Fritz%") ) /* misspelled property */
.Add( Expression.Between("Weight", minWeight, maxWeight) )
.List();

Related

"LINQ to Entities does not recognize the method" without using local

I want to query count of selected products with a Combobox in VB.NET, Linq and Entity Framework 6. This query generates error (cmbProducts is a Combobox):
Dim Count = (From Product In db.Products
Where Product.Type = cmbProducts.SelectedValue
).Count
And this is the error:
LINQ to Entities does not recognize the method 'System.Object CompareObjectEqual(System.Object, System.Object, Boolean)' method, and this method cannot be translated into a store expression.
But when I run this query with db.Products.local, it executes without any errors:
Dim Count = (From Product In db.Products.local
Where Product.Type = cmbProducts.SelectedValue
).Count
You really should turn Option Strict On in the project properties and also in the IDE options, so it will be On by default for all future projects. If you do that then that code won't even compile. That would force you to do as you should have and cast the SelectedValue, which is type Object, as the actual type of the underlying object, which is presumably String or Integer. You can use DirectCast or else CInt, CStr or the like to perform the cast, e.g.
Where Product.Type = CInt(cmbProducts.SelectedValue)
Ideally, you should be assigning the result of that cast to a variable and using that in your LINQ query. It's important to remember that, while LINQ syntax is always the same, each LINQ provider has a different implementation. LINQ to Entities converts your query to SQL that it can execute against the database and that means that some things that are supported by LINQ in general, and will thus compile, will actually fail at run-time against LINQ to Entities. It's generally a good idea to keep anything remotely exotic out of your EF queries. You'd probably be OK in this case but it's a good habit to get into as it can help avoid subtle issues.
Make sure they are of the same type.
I think Product.Type is a string but cmbProducts.SelectedValue is an int, try to use cmbProducts.SelectedItem.Text
When comparing locally .Net will be able to compare them by SQL Server may not.

Querydsl selecting from a subquery runtime exception

I'm stuck on how to select from a subquery using Querydsl on SQL. The code compiles fine, but I'm getting a runtime exception: Undeclared path 'cases'. Add this path as a source to the query to be able to reference it.
The code looks approximately like this:
private ListSubQuery<Integer> getStudyCaseSubQuery(CaseQuery query) {
SQLSubQuery sq = new SQLSubQuery().from(cases);
... stuff happens
return sq.list(cases.id);
}
...
public List<JsonObject> getData(...) {
// Build a common subquery for a bunch of other queries
ListSubQuery<Integer> caseQuery = getStudyCaseSubQuery(...);
// This fails with runtime exception
List<Integer> caseIds = caseQuery.list(Expressions.path(Integer.class, cases, "id"));
}
I can see where the problem is: I can't find a way to specify an alias for the subquery apart from a whole table, which isn't the case here. There's a bunch of examples that use Alias and Path but nothing that matches in the tests or tutorials that I can adapt to this problem. Although I know SQL pretty well, aliasing tables and columns appear entirely different in Querydsl, but the examples I've found don't really elaborate on the differences, so clarification would be extremely helpful.

How to run a function using a nhibernate criteria?

We have a search routine that uses criteria to build SQL query (because its restrictions added dynamically).
In a particular case (a very complicated case) we need to search over a table-valued function.(our model object is mapped to the function).
The result would be something like this :
SELECT count(*) FROM dbo.GetSubStaffsLetterInstances(#staffId) WHERE LetterNumber="1234";
The problem is I don't know how to pass #staffId to my criteria(I tried adding an Eq restrictions without success since restrictions are working on properties)
I know I can add a parameter to an IQuery but I don't know how I can do it using an ICriteria object.
If I understand your question completely, you can resort back to standard SQL:-
var sql = "SELECT count(*) FROM dbo.GetSubStaffsLetterInstances(:staffId)
WHERE LetterNumber=:letterNum";
var count = session.CreateSqlQuery(sql)
.setInt32("staffId", 12345)
.setString("letternum", "A1")
.UniqueResult<int>();
or try .UniqueResult<long>(); as I can't remember which one HQL returns

Rails and SQL Injection: Is this safe?

#usersfound = User.find_by_sql(["
SELECT * from users where name ## plainto_tsquery('english', ?) LIMIT 20 offset ?
",#query,#offset])
See above, is this safe from sql injection? I am very new to doing direct sql commands on a database in rails. (I am aware there may be other ways of doing this SPECIFIC query, but I am wondering if in general, using find_by_sql and that kind of insertion of vars is safe - I have some difficult queries with subselects and joins that are really possible to do with ActiveRecord.
Thanks.
Yes, that should be safe. If you trace through the code you'll find that your find_by_sql call ends up calling PGconn#send_query_prepared with the bind parameters being carried along as little more than baggage; the send_query_prepared method is just a wrapper for the PQsendQueryPrepared API call in libpq:
static VALUE
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
{
/* ... bunch of boiler plate marshalling stuff ... */
result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
(const char * const *)paramValues, paramLengths, paramFormats,
resultFormat);
/* ... */
}
The bind parameters end up in paramValues. So you should be fine unless there are bugs in PostgreSQL's C library prepared statement handling.
Inserting dynamic values into a query using query parameters is safe.
But it depends on whether Rails is "faking" query parameters, and is actually combining #query and #offset into the SQL string before preparing the statement. Then it's only as safe as the implementation of escaping in Rails.

Why doesn't a separately instantiated Func<T,bool> predicate not translate into SQL with Entity Framework?

I have an EF Code First Db context that I'm using to query the database. I noticed some performance issues when passing in queries as Func<Product, bool>s from my Aggregate Repository and on investigating further it turned out that the queries were not being translated into SQL Queries.
After a little more digging I discovered the following.
var results = _context.Products
.Where(p => p.ProductCode.Contains("AAA"))
.Where(p => p.CategoryId == 1)
.ToList();
This works exactly as expected. It generates some parametrized SQL with a Where Clause.
==================================================================
var results2 = _context.Products
.Where(p => p.ProductCode.Contains("AAA") && p.CategoryId == 1)
.ToList();
This also works as expected. It generates the same sql as above
==================================================================
Func<Product, bool> pred = (p => p.ProductCode.Contains("AAA") && p.CategoryId == 1);
var results3 = _context.Products.Where(pred).ToList();
This is broken. It doesn't generate the where clause in the SQL, it returns everything and then filters it in code.
Because in order to translate into SQL, it has to be an Expression<...>, not a Func<...>.
This is done automatically for you by the compiler, and since the overloads on the Linq-to-SQL classes takes expressions, not delegates, the compiler will automagically translate your code (which looks like a lambda or an anonymous method) into an expression object and pass that.
However, if you take care of building the function yourself, the compiler cannot do this, and Linq-to-SQL does not take anonymous methods, it only takes expressions.
What you can do is to execute the parts of your query that you can, and then filter the results through your function, but I would look into just changing the type of your value into an expression instead.
No sooner than I posted this ReSharper helped answer my question by showing me the overload method signature for the Where() extension method.
It takes both Func<T, bool> and Expression<Func<T, bool>>. If your declaring your predicates externally, you must use the Expression variation as the former is not translated into sql.
Here's why the query reads the whole table.
When a Func is used instead of an Expression, the compiler chooses methods on System.Linq.Enumerable - instead of System.Linq.Queryable. The Enumerable methods iterate the source collection (sometimes lazily) while the Queryable methods build up the expression tree.
Since the call to Where isn't part of the expression tree, the sql generator doesn't see it during the query translation.