From: <pa...@us...> - 2010-11-28 20:14:08
|
Revision: 5280 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5280&view=rev Author: patearl Date: 2010-11-28 20:14:01 +0000 (Sun, 28 Nov 2010) Log Message: ----------- Linq: Let HQL figure out the type of non-null parameters. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/A.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/EnumStringUserType.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumber.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumberUserType.cs Modified: trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2010-11-28 19:18:45 UTC (rev 5279) +++ trunk/nhibernate/src/NHibernate/Linq/NhQueryProvider.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -137,9 +137,13 @@ { query.SetParameterList(parameterName, (ICollection) param.First); } + else if (param.Second != null) + { + query.SetParameter(parameterName, param.First, param.Second); + } else { - query.SetParameter(parameterName, param.First); + query.SetParameter(parameterName, param.First); } } } Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2010-11-28 19:18:45 UTC (rev 5279) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionParameterVisitor.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using NHibernate.Type; namespace NHibernate.Linq.Visitors { @@ -25,7 +26,20 @@ { if (!typeof(IQueryable).IsAssignableFrom(expression.Type) && !IsNullObject(expression)) { - _parameters.Add(expression, new NamedParameter("p" + (_parameters.Count + 1), expression.Value, NHibernateUtil.GuessType(expression.Type))); + // We use null for the type to indicate that the caller should let HQL figure it out. + IType type = null; + + // We have a bit more information about the null parameter value. + // Figure out a type so that HQL doesn't break on the null. (Related to NH-2430) + if (expression.Value == null) + type = NHibernateUtil.GuessType(expression.Type); + + // There is more information available in the Linq expression than to HQL directly. + // In some cases it might be advantageous to use the extra info. Assuming this + // comes up, it would be nice to combine the HQL parameter type determination code + // and the Expression information. + + _parameters.Add(expression, new NamedParameter("p" + (_parameters.Count + 1), expression.Value, type)); } return base.VisitConstantExpression(expression); Property changes on: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394 ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/A.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/A.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/A.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,30 @@ +using System; +using System.Collections; + +namespace NHibernate.Test.NHSpecificTest.NH2394 +{ + public interface IA + { + int? Id { get; set; } + TypeOfA Type { get; set; } + TypeOfA? NullableType { get; set; } + PhoneNumber Phone { get; set; } + bool IsNice { get; set; } + } + + public class A : IA + { + public int? Id { get; set; } + public TypeOfA Type { get; set; } + public TypeOfA? NullableType { get; set; } + public PhoneNumber Phone { get; set; } + public bool IsNice { get; set; } + } + + public enum TypeOfA + { + Awesome, + Boring, + Cool + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/EnumStringUserType.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/EnumStringUserType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/EnumStringUserType.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using NHibernate.SqlTypes; +using NHibernate.Type; +using NHibernate.UserTypes; + +namespace NHibernate.Test.NHSpecificTest.NH2394 +{ + public class EnumStringUserType : EnumStringType<TypeOfA> + { + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Fixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Fixture.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using NHibernate.Criterion; +using NUnit.Framework; +using NHibernate.Linq; +using System.Linq; +using NHibernate.Linq.Functions; + +namespace NHibernate.Test.NHSpecificTest.NH2394 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnTearDown() + { + using (ISession s = sessions.OpenSession()) + { + s.Delete("from A"); + s.Flush(); + } + } + + [Test] + public void LinqUserTypeEquality() + { + ISession s = OpenSession(); + try + { + s.Save(new A { Type = TypeOfA.Awesome, Phone = new PhoneNumber(1, "555-1111") }); + s.Save(new A { Type = TypeOfA.Boring, NullableType = TypeOfA.Awesome, Phone = new PhoneNumber(1, "555-2222") }); + s.Save(new A { Type = TypeOfA.Cool, Phone = new PhoneNumber(1, "555-3333") }); + s.Flush(); + } + finally + { + s.Close(); + } + + s = OpenSession(); + try + { + A item; + + Assert.AreEqual(3, s.CreateQuery("from A a where a.IsNice = ?").SetParameter(0, false).List().Count); + Assert.AreEqual(3, s.Query<A>().Count(a => a.IsNice == false)); + + item = s.CreateQuery("from A a where a.Type = ?").SetParameter(0, TypeOfA.Awesome).UniqueResult<A>(); + Assert.AreEqual(TypeOfA.Awesome, item.Type); + Assert.AreEqual("555-1111", item.Phone.Number); + + item = s.Query<A>().Where(a => a.Type == TypeOfA.Awesome).Single(); + Assert.AreEqual(TypeOfA.Awesome, item.Type); + Assert.AreEqual("555-1111", item.Phone.Number); + + item = s.Query<A>().Where(a => TypeOfA.Awesome == a.Type).Single(); + Assert.AreEqual(TypeOfA.Awesome, item.Type); + Assert.AreEqual("555-1111", item.Phone.Number); + + IA interfaceItem = s.Query<IA>().Where(a => a.Type == TypeOfA.Awesome).Single(); + Assert.AreEqual(TypeOfA.Awesome, interfaceItem.Type); + Assert.AreEqual("555-1111", interfaceItem.Phone.Number); + + item = s.CreateQuery("from A a where a.NullableType = ?").SetParameter(0, TypeOfA.Awesome).UniqueResult<A>(); + Assert.AreEqual(TypeOfA.Boring, item.Type); + Assert.AreEqual("555-2222", item.Phone.Number); + Assert.AreEqual(TypeOfA.Awesome, item.NullableType); + + item = s.Query<A>().Where(a => a.NullableType == TypeOfA.Awesome).Single(); + Assert.AreEqual(TypeOfA.Boring, item.Type); + Assert.AreEqual("555-2222", item.Phone.Number); + Assert.AreEqual(TypeOfA.Awesome, item.NullableType); + + Assert.AreEqual(2, s.Query<A>().Count(a => a.NullableType == null)); + + item = s.CreateQuery("from A a where a.Phone = ?").SetParameter(0, new PhoneNumber(1, "555-2222")).UniqueResult<A>(); + Assert.AreEqual(TypeOfA.Boring, item.Type); + Assert.AreEqual("555-2222", item.Phone.Number); + + item = s.Query<A>().Where(a => a.Phone == new PhoneNumber(1, "555-2222")).Single(); + Assert.AreEqual(TypeOfA.Boring, item.Type); + Assert.AreEqual("555-2222", item.Phone.Number); + } + finally + { + s.Close(); + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/Mappings.hbm.xml 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test" namespace="NHibernate.Test.NHSpecificTest.NH2394"> + <class name="A" table="a" lazy="false" optimistic-lock="dirty" dynamic-update="true"> + <id name="Id" column="id" unsaved-value="null"> + <generator class="native" /> + </id> + <property name="Phone" type="NHibernate.Test.NHSpecificTest.NH2394.PhoneNumberUserType, NHibernate.Test"> + <column name="PhoneCountryCode"/> + <column name="PhoneNumber"/> + </property> + <property name="Type" type="NHibernate.Test.NHSpecificTest.NH2394.EnumStringUserType, NHibernate.Test"/> + <property name="NullableType" type="NHibernate.Test.NHSpecificTest.NH2394.EnumStringUserType, NHibernate.Test"/> + <property name="IsNice" type="TrueFalse"/> + </class> +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumber.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumber.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumber.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NHibernate.Test.NHSpecificTest.NH2394 +{ + public class PhoneNumber + { + public PhoneNumber(int countryCode, string number) + { + CountryCode = countryCode; + Number = number; + } + + public int CountryCode { get; private set; } + public string Number { get; private set; } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + + if (obj.GetType() != GetType()) + return false; + + PhoneNumber that = (PhoneNumber) obj; + + return + CountryCode == that.CountryCode && + Number == that.Number; + } + + public override int GetHashCode() + { + return CountryCode.GetHashCode() ^ (Number ?? "").GetHashCode(); + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumberUserType.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumberUserType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2394/PhoneNumberUserType.cs 2010-11-28 20:14:01 UTC (rev 5280) @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using NHibernate.Engine; +using NHibernate.Type; +using NHibernate.UserTypes; + +namespace NHibernate.Test.NHSpecificTest.NH2394 +{ + class PhoneNumberUserType : ICompositeUserType + { + public string[] PropertyNames + { + get { return new[] { "CountryCode", "Number" }; } + } + + public IType[] PropertyTypes + { + get { return new[] { NHibernateUtil.Int32, NHibernateUtil.String }; } + } + + public object GetPropertyValue(object component, int property) + { + PhoneNumber phone = (PhoneNumber)component; + + switch (property) + { + case 0: return phone.CountryCode; + case 1: return phone.Number; + default: throw new NotImplementedException(); + } + } + + public void SetPropertyValue(object component, int property, object value) + { + throw new NotImplementedException(); + } + + public System.Type ReturnedClass + { + get { return typeof(PhoneNumber); } + } + + bool ICompositeUserType.Equals(object x, object y) + { + if (ReferenceEquals(x, null) && ReferenceEquals(y, null)) + return true; + + if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) + return false; + + return x.Equals(y); + } + + public int GetHashCode(object x) + { + return x.GetHashCode(); + } + + public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner) + { + if (dr.IsDBNull(dr.GetOrdinal(names[0]))) + return null; + + return new PhoneNumber( + (int)NHibernateUtil.Int32.NullSafeGet(dr, names[0], session, owner), + (string)NHibernateUtil.String.NullSafeGet(dr, names[1], session, owner)); + } + + public void NullSafeSet(IDbCommand cmd, object value, int index, bool[] settable, ISessionImplementor session) + { + object countryCode = value == null ? null : (int?)((PhoneNumber)value).CountryCode; + object number = value == null ? null : ((PhoneNumber)value).Number; + + if (settable[0]) NHibernateUtil.Int32.NullSafeSet(cmd, countryCode, index++, session); + if (settable[1]) NHibernateUtil.String.NullSafeSet(cmd, number, index, session); + } + + public object DeepCopy(object value) + { + return value; + } + + public bool IsMutable + { + get { return false; } + } + + public object Disassemble(object value, ISessionImplementor session) + { + return value; + } + + public object Assemble(object cached, ISessionImplementor session, object owner) + { + return cached; + } + + public object Replace(object original, object target, ISessionImplementor session, object owner) + { + return original; + } + } +} Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-11-28 19:18:45 UTC (rev 5279) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-11-28 20:14:01 UTC (rev 5280) @@ -543,6 +543,11 @@ <Compile Include="NHSpecificTest\NH2392\Fixture.cs" /> <Compile Include="NHSpecificTest\NH2392\PhoneNumber.cs" /> <Compile Include="NHSpecificTest\NH2392\PhoneNumberUserType.cs" /> + <Compile Include="NHSpecificTest\NH2394\A.cs" /> + <Compile Include="NHSpecificTest\NH2394\EnumStringUserType.cs" /> + <Compile Include="NHSpecificTest\NH2394\Fixture.cs" /> + <Compile Include="NHSpecificTest\NH2394\PhoneNumber.cs" /> + <Compile Include="NHSpecificTest\NH2394\PhoneNumberUserType.cs" /> <Compile Include="NHSpecificTest\NH2409\Contest.cs" /> <Compile Include="NHSpecificTest\NH2409\Fixture.cs" /> <Compile Include="NHSpecificTest\NH2409\Message.cs" /> @@ -2329,6 +2334,7 @@ <EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="NHSpecificTest\NH2394\Mappings.hbm.xml" /> <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> <EmbeddedResource Include="Any\Person.hbm.xml" /> <EmbeddedResource Include="Any\Properties.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |