-
Notifications
You must be signed in to change notification settings - Fork 934
Incorrect SQL when comparing a guid and string column in Sql Server #2040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
May be related to #2029 (or maybe have the same root cause), and could be fixed by #2036 (which does also some changes on a path not specific to @micmerchant, if you can tell from which minor version the trouble has appeared (only 5.2, or 5.1 too, or 5.0 too, or 4.1 too if you were using 4.0), we would appreciate it. |
I've checked the issue and #2036 does not solve the problem. The issue was introduced with #1856 by adding the following lines: nhibernate-core/src/NHibernate/Linq/Functions/StringGenerator.cs Lines 329 to 332 in 39bf753
I will analyze the mentioned PR and try to find a general solution. |
You are right. This only happens in context of Guids. @fredericDelaporte We are updating from NHibernate 4.0.3. |
What about simply adding a custom function to the MsSql2000Dialect.cs class? e.g. public class MsSql2000Dialect : Dialect
{
...
protected virtual void RegisterFunctions()
{
...
// after
RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as nvarchar(50))"));
// new one
RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as nvarchar(50))"));
...
}
...
} which overrides the one from the general Dialect.cs class? RegisterFunction("strguid", new SQLFunctionTemplate(NHibernateUtil.String, "?1")); |
@micmerchant Just to know, Which version of MS SQL are you using? @maca88 Probably is missing the code this code, on class
Like @micmerchant mention, |
@lillo42 |
Indeed, registering |
Well, we are using a custom NHibernate build anyways, which means that I can apply this fix directly in our code base. So I'm fine with adding it in the 5.2.5 release. |
@maca88 [Test]
public void CompareStringColumnWithGuidToString()
{
using (var session = OpenSession())
{
var list = session.Query<Entity>()
.Where(x => x.Id.ToString() == x.Name)
.ToList();
Assert.That(list, Has.Count.EqualTo(0));
}
} and the simplicity of reproduction of the bug. I thought this was all about using guids and strings in a join context. But i was misleaded by my own unit tests. I had a similar one, which didn't fail. [Test(Description = "This test checks a string cast of a not nullable guid column in the where condition.")]
public void NotNullableGuidToStringWithEqualsOperatorComparisonInWhereConditionMethodSyntaxTest1()
{
INHibernateSession session = NHibernateSessionManager.Instance.GetSession();
string vehicleId = VehicleInitializer.SomeVehicleId.ToString();
var result = session.Query<IVehicle>()
.Where(v => v.ID.ToString() == vehicleId)
.ToList();
} It didn't fail because the sequal server of course supports this kind of comparison, because the other side is a Guid already. By changing vehicleId to a string e.g. "Test", it would fail. So the query of the unit test above, gets translated into this: select vehicle0_.ID as id1_631_,
....
from Vehicle vehicle0_
where (vehicle0_.[Mandator] & -1 /* @p0 */) != 0
and cast(vehicle0_.ID as nvarchar(50)) = 'eca27f3a-42bb-4b72-a481-ad8f8a40ce69' /* @p1 - cle0_.ID as nvarchar(50)) */ And here I'm asking myself now, if it wouldn't be an improvement if the query translator would check the type of both sides of the comparison and then decides if a string cast is necessary at all. E.g. if the constant is already a valid Guid then a cast wouldn't be necessary. What do you think? |
Yes it would be an improvement, maybe by introducing a special logic that would avoid common "mistakes" made by the user like the example that you provided, which in this case would produce the same sql as the following query:
of course the logic would need to be dialect specific. |
From that point of view, you are absolutly right :) It would only hide a mistake in the written query code, which you would never recognize e.g. via the NHibernateProfiler. And i can't come up with a better example. Thx a lot. |
Hello,
we are currently updating from an old NHibernate 4 version to the current NHibernate 5 (5.2.3) version and are facing some issues.
One of our models contains a nullable string column which is joined on a column with a different type of an other table by using ToString() within the join, e.g:
This worked in NHibernate 4 but fails in NHibernate 5. Here is a logged query example from our production code with
Join-Exception.txt
NHibernate 4 and NHibernate 5.
It looks like that the .ToString() cast isn't translated into SQL anymore. This only happens when the string column is nullable. I guess the query translator recognizes that a cast isn't necessary for not nullable string columns.
This problem is reproducable with a unit test with the northwind domainmodel:
I've also attached the unit test exception.
Thx in advance. Best regards!
Join-Exception.txt
The text was updated successfully, but these errors were encountered: