From: <te...@us...> - 2008-11-02 18:28:35
|
Revision: 3884 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3884&view=rev Author: tehlike Date: 2008-11-02 18:28:25 +0000 (Sun, 02 Nov 2008) Log Message: ----------- Applying patch from Michael Montgomery with modifications (fix NH-1233) Introducing Enums with Char DB backend. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Type/EnumCharType.cs trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.cs trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.hbm.xml trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharTypeFixture.cs Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-11-02 17:37:44 UTC (rev 3883) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2008-11-02 18:28:25 UTC (rev 3884) @@ -1053,6 +1053,7 @@ <Compile Include="Type\CollectionType.cs" /> <Compile Include="Type\CustomCollectionType.cs" /> <Compile Include="Type\EmbeddedComponentType.cs" /> + <Compile Include="Type\EnumCharType.cs" /> <Compile Include="Type\EnumStringType`1.cs" /> <Compile Include="Type\GenericOrderedSetType.cs" /> <Compile Include="Type\ICacheAssembler.cs" /> Added: trunk/nhibernate/src/NHibernate/Type/EnumCharType.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Type/EnumCharType.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Type/EnumCharType.cs 2008-11-02 18:28:25 UTC (rev 3884) @@ -0,0 +1,184 @@ +using System; +using System.Data; +using NHibernate.Engine; +using NHibernate.SqlTypes; + +namespace NHibernate.Type +{ + [Serializable] + public class EnumCharType<T> : ImmutableType, IDiscriminatorType + { + + public EnumCharType() : base(new StringFixedLengthSqlType(1)) + { + if (typeof(T).IsEnum) + { + this.enumClass = typeof(T); + } + else + { + throw new MappingException(enumClass.Name + " did not inherit from System.Enum"); + } + } + private readonly System.Type enumClass; + + public virtual object GetInstance(object code) + { + if (code is String) + { + return GetInstanceFromString((String) code); + } + else if (code is Char) + { + return GetInstanceFromChar((Char) code); + } + else + { + throw new HibernateException(string.Format("Can't Parse {0} as {1}", code, enumClass.Name)); + } + } + + private object GetInstanceFromString(String s) + { + if (s.Length == 0) throw new HibernateException(string.Format("Can't Parse empty string as {0}", enumClass.Name)); + + if (s.Length == 1) + { + //String representation of underlying char value e.g. "R" + return GetInstanceFromChar(s[0]); + } + else + { + //Name of enum value e.g. "Red" + try + { + return Enum.Parse(enumClass, s, false); + } + catch (ArgumentException) + { + try + { + return Enum.Parse(enumClass, s, true); + } + catch (ArgumentException ae) + { + throw new HibernateException(string.Format("Can't Parse {0} as {1}", s, enumClass.Name), ae); + } + } + } + } + + private object GetInstanceFromChar(Char c) + { + Object instance; + + instance = Enum.ToObject(enumClass, c); + if (Enum.IsDefined(enumClass, instance)) return instance; + + instance = Enum.ToObject(enumClass, Alternate(c)); + if (Enum.IsDefined(enumClass, instance)) return instance; + + throw new HibernateException(string.Format("Can't Parse {0} as {1}", c, enumClass.Name)); + } + + private Char Alternate(Char c) + { + return Char.IsUpper(c) ? Char.ToLower(c) : Char.ToUpper(c); + } + + /// <summary> + /// Converts the given enum instance into a basic type. + /// </summary> + /// <param name="instance"></param> + /// <returns></returns> + public virtual object GetValue(object instance) + { + if (instance == null) + { + return null; + } + else + { + return (Char) (Int32) instance; + } + } + + public override System.Type ReturnedClass + { + get { return enumClass; } + } + + public override void Set(IDbCommand cmd, object value, int index) + { + IDataParameter par = (IDataParameter) cmd.Parameters[index]; + if (value == null) + { + par.Value = DBNull.Value; + } + else + { + par.Value = ((Char) (Int32) (value)).ToString(); + } + } + + public override object Get(IDataReader rs, int index) + { + object code = rs[index]; + if (code == DBNull.Value || code == null) + { + return null; + } + else + { + return GetInstance(code); + } + } + + public override object Get(IDataReader rs, string name) + { + return Get(rs, rs.GetOrdinal(name)); + } + + public override string Name + { + get { return "enumchar - " + enumClass.Name; } + } + + public override string ToString(object value) + { + return (value == null) ? null : GetValue(value).ToString(); + } + + public override object Assemble(object cached, ISessionImplementor session, object owner) + { + if (cached == null) + { + return null; + } + else + { + return GetInstance(cached); + } + } + + public override object Disassemble(object value, ISessionImplementor session, object owner) + { + return (value == null) ? null : GetValue(value); + } + + public virtual object StringToObject(string xml) + { + return (string.IsNullOrEmpty(xml)) ? null : FromStringValue(xml); + } + + public override object FromStringValue(string xml) + { + return GetInstance(xml); + } + + public virtual string ObjectToSQLString(object value, Dialect.Dialect dialect) + { + return '\'' + GetValue(value).ToString() + '\''; + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-02 17:37:44 UTC (rev 3883) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2008-11-02 18:28:25 UTC (rev 3884) @@ -885,6 +885,8 @@ <Compile Include="TypesTest\DoubleTypeFixture.cs" /> <Compile Include="TypesTest\EntityClass.cs" /> <Compile Include="TypesTest\EntityTypeFixture.cs" /> + <Compile Include="TypesTest\EnumCharClass.cs" /> + <Compile Include="TypesTest\EnumCharTypeFixture.cs" /> <Compile Include="TypesTest\EnumStringClass.cs" /> <Compile Include="TypesTest\EnumStringTypeFixture.cs" /> <Compile Include="TypesTest\GuidClass.cs" /> @@ -1509,6 +1511,7 @@ <EmbeddedResource Include="Cascade\JobBatch.hbm.xml" /> <EmbeddedResource Include="Deletetransient\Person.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="TypesTest\EnumCharClass.hbm.xml" /> <EmbeddedResource Include="Extendshbm\packageentitynamesWithColl.hbm.xml" /> <EmbeddedResource Include="Extendshbm\entitynamesWithColl.hbm.xml" /> <EmbeddedResource Include="Extendshbm\packageentitynamesf1.hbm.xml" /> Added: trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.cs 2008-11-02 18:28:25 UTC (rev 3884) @@ -0,0 +1,62 @@ +using System; +using NHibernate.Type; + +namespace NHibernate.Test.TypesTest +{ + public class EnumCharClass + { + private int _id; + private SampleCharEnum _enumValue; + + public int Id + { + get { return _id; } + set { _id = value; } + } + + public SampleCharEnum EnumValue + { + get { return _enumValue; } + set { _enumValue = value; } + } + } + + public enum SampleCharEnum + { + On = 'N', + Off = 'F', + Dimmed = 'D' + } + + + public class EnumCharFoo + { + private Int32 id; + + public virtual Int32 Id + { + get { return id; } + set { id = value; } + } + } + + public class EnumCharBar : EnumCharFoo {} + + public class EnumCharBaz + { + private Int32 id; + private SampleCharEnum type; + + public virtual Int32 Id + { + get { return id; } + set { id = value; } + } + + public virtual SampleCharEnum Type + { + get { return type; } + set { type = value; } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharClass.hbm.xml 2008-11-02 18:28:25 UTC (rev 3884) @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" namespace="NHibernate.Test.TypesTest" assembly="NHibernate.Test"> + <class name="EnumCharClass" table="bc_echr"> + <id name="Id"> + <generator class="assigned" /> + </id> + <property name="EnumValue" type="NHibernate.Type.EnumCharType`1[[NHibernate.Test.TypesTest.SampleCharEnum, NHibernate.Test]], NHibernate" column="enumc"/> + </class> + <class name="EnumCharFoo" table="bc_ecfoobarbaz" discriminator-value="Dimmed"> + <id name="Id"> + <generator class="assigned"/> + </id> + <discriminator type="NHibernate.Type.EnumCharType`1[[NHibernate.Test.TypesTest.SampleCharEnum, NHibernate.Test]], NHibernate" column="type"/> + <subclass name="EnumCharBar" discriminator-value="Off"/> + </class> + + <class name="EnumCharBaz" table="bc_ecfoobarbaz"> + <id name="Id"> + <generator class="assigned"/> + </id> + <property name="Type" column="type" type="NHibernate.Type.EnumCharType`1[[NHibernate.Test.TypesTest.SampleCharEnum, NHibernate.Test]], NHibernate"/> + </class> +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharTypeFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharTypeFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/TypesTest/EnumCharTypeFixture.cs 2008-11-02 18:28:25 UTC (rev 3884) @@ -0,0 +1,146 @@ +using System.Collections; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.TypesTest +{ + [TestFixture] + public class EnumCharTypeFixture : TypeFixtureBase + { + protected override string TypeName + { + get { return "EnumChar"; } + } + + protected override void OnSetUp() + { + + EnumCharClass basic = new EnumCharClass(); + basic.Id = 1; + basic.EnumValue = SampleCharEnum.Dimmed; + + EnumCharClass basic2 = new EnumCharClass(); + basic2.Id = 2; + basic2.EnumValue = SampleCharEnum.On; + + ISession s = OpenSession(); + s.Save(basic); + s.Save(basic2); + s.Flush(); + s.Close(); + } + + protected override void OnTearDown() + { + ISession s = OpenSession(); + s.Delete("from EnumCharClass"); + s.Delete("from EnumCharBaz"); + s.Flush(); + s.Close(); + } + + [Test] + public void ReadFromLoad() + { + using (ISession s = OpenSession()) + { + EnumCharClass basic = (EnumCharClass) s.Load(typeof (EnumCharClass), 1); + Assert.AreEqual(SampleCharEnum.Dimmed, basic.EnumValue); + + EnumCharClass basic2 = (EnumCharClass) s.Load(typeof (EnumCharClass), 2); + Assert.AreEqual(SampleCharEnum.On, basic2.EnumValue); + } + } + + [Test] + public void ReadFromQueryUsingValue() + { + using (ISession s = OpenSession()) + { + IList results; + IQuery q = s.CreateQuery("from EnumCharClass as ecc where ecc.EnumValue=:value"); + + q.SetParameter("value", SampleCharEnum.On,new EnumCharType<SampleCharEnum>()); + results = q.List(); + + Assert.AreEqual(1, results.Count, "only 1 was 'On'"); + + q.SetParameter("value", SampleCharEnum.Off, new EnumCharType<SampleCharEnum>()); + results = q.List(); + + Assert.AreEqual(0, results.Count, "should not be any in the 'Off' status"); + } + } + + [Test] + public void ReadFromQueryUsingString() + { + using (ISession s = OpenSession()) + { + IList results; + IQuery q = s.CreateQuery("from EnumCharClass as ecc where ecc.EnumValue=:value"); + + q.SetString("value", "N"); + results = q.List(); + + Assert.AreEqual(1, results.Count, "only 1 was \"N\" string"); + + q.SetString("value", "F"); + results = q.List(); + + Assert.AreEqual(0, results.Count, "should not be any in the \"F\" string"); + } + } + + [Test] + public void ReadFromQueryUsingChar() + { + using (ISession s = OpenSession()) + { + IList results; + IQuery q = s.CreateQuery("from EnumCharClass as ecc where ecc.EnumValue=:value"); + + q.SetCharacter("value", 'N'); + results = q.List(); + + Assert.AreEqual(1, results.Count, "only 1 was 'N' char"); + + q.SetCharacter("value", 'F'); + results = q.List(); + + Assert.AreEqual(0, results.Count, "should not be any in the 'F' char"); + } + } + + [Test] + public void CanBeUsedAsDiscriminator() + { + EnumCharFoo foo = new EnumCharFoo(); + EnumCharBar bar = new EnumCharBar(); + + foo.Id = 1; + bar.Id = 2; + + using (ISession s = OpenSession()) + { + s.Save(foo); + s.Save(bar); + s.Flush(); + } + + using (ISession s = OpenSession()) + { + s.Load<EnumCharFoo>(1); + s.Load<EnumCharBar>(2); + + EnumCharBaz baz; + + baz = s.Load<EnumCharBaz>(1); + Assert.AreEqual(SampleCharEnum.Dimmed, baz.Type); + + baz = s.Load<EnumCharBaz>(2); + Assert.AreEqual(SampleCharEnum.Off, baz.Type); + } + } + } +} \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |