|
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.
|