From: <fab...@us...> - 2008-07-21 04:50:01
|
Revision: 3642 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=3642&view=rev Author: fabiomaulo Date: 2008-07-21 04:49:58 +0000 (Mon, 21 Jul 2008) Log Message: ----------- - Enabled <tuplizer> (NH-1397) - Fix NH-1395 - Fix NH-1396 Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Cfg/HbmConstants.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -48,5 +48,6 @@ public const string nsResultset = nsPrefix + ":resultset"; public const string nsUnionSubclass = nsPrefix + ":union-subclass"; + public const string nsTuplizer = nsPrefix + ":tuplizer"; } } Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/ClassBinder.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -106,36 +106,32 @@ protected void BindClass(XmlNode node, PersistentClass model) { - string className = node.Attributes["name"] == null ? null : FullClassName(node.Attributes["name"].Value, mappings); + // transfer an explicitly defined entity name + // handle the lazy attribute + XmlAttribute lazyNode = node.Attributes["lazy"]; + bool lazy = lazyNode == null ? mappings.DefaultLazy : "true".Equals(lazyNode.Value); + // go ahead and set the lazy here, since pojo.proxy can override it. + model.IsLazy = lazy; - // CLASS - model.ClassName = ClassForFullNameChecked(className, "persistent class {0} not found").AssemblyQualifiedName; - - string entityName = node.Attributes["entity-name"] == null ? null : node.Attributes["name"].Value; + string entityName = (node.Attributes["entity-name"] != null ? node.Attributes["entity-name"].Value : null) + ?? + ClassForNameChecked(node.Attributes["name"].Value, mappings, "persistent class {0} not found"). + FullName; if (entityName == null) - entityName = model.MappedClass.FullName; - if (entityName == null) { throw new MappingException("Unable to determine entity name"); } model.EntityName = entityName; - // PROXY INTERFACE - XmlAttribute proxyNode = node.Attributes["proxy"]; - XmlAttribute lazyNode = node.Attributes["lazy"]; - bool lazy = lazyNode == null ? mappings.DefaultLazy : "true".Equals(lazyNode.Value); + BindPocoRepresentation(node, model); + BindXmlRepresentation(node, model); + BindMapRepresentation(node, model); - // go ahead and set the lazy here, since pojo.proxy can override it. - model.IsLazy = lazy; + BindPersistentClassCommonValues(node, model); + } - if (proxyNode != null) - { - model.ProxyInterfaceName = ClassForNameChecked(proxyNode.Value, mappings, "proxy class not found: {0}").AssemblyQualifiedName; - model.IsLazy = true; - } - else if (model.IsLazy) - model.ProxyInterfaceName = model.MappedClass.AssemblyQualifiedName; - + private void BindPersistentClassCommonValues(XmlNode node, PersistentClass model) + { // DISCRIMINATOR XmlAttribute discriminatorNode = node.Attributes["discriminator-value"]; model.DiscriminatorValue = (discriminatorNode == null) ? model.EntityName : discriminatorNode.Value; @@ -179,8 +175,8 @@ //persister = typeof( EntityPersister ); } else - model.EntityPersisterClass = - ClassForNameChecked(persisterNode.Value, mappings, "could not instantiate persister class: {0}"); + model.EntityPersisterClass = ClassForNameChecked(persisterNode.Value, mappings, + "could not instantiate persister class: {0}"); // CUSTOM SQL HandleCustomSQL(node, model); @@ -200,6 +196,71 @@ model.IsAbstract = isAbstract; } + private void BindMapRepresentation(XmlNode node, PersistentClass entity) + { + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Map); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Map, tupClassName); + } + } + + private void BindXmlRepresentation(XmlNode node, PersistentClass entity) + { + string nodeName = null; + XmlAttribute nodeAtt = node.Attributes["node"]; + if(nodeAtt != null) + nodeName = nodeAtt.Value; + if (nodeName == null) + nodeName = StringHelper.Unqualify(entity.EntityName); + entity.NodeName = nodeName; + + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Xml); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Xml, tupClassName); + } + } + + private void BindPocoRepresentation(XmlNode node, PersistentClass entity) + { + string className = node.Attributes["name"] == null + ? null + : ClassForNameChecked(node.Attributes["name"].Value, mappings, "persistent class {0} not found"). + AssemblyQualifiedName; + + entity.ClassName = className; + + XmlAttribute proxyNode = node.Attributes["proxy"]; + if (proxyNode != null) + { + entity.ProxyInterfaceName = ClassForNameChecked(proxyNode.Value, mappings, "proxy class not found: {0}").AssemblyQualifiedName; + entity.IsLazy = true; + } + else if (entity.IsLazy) + entity.ProxyInterfaceName = className; + + XmlNode tuplizer = LocateTuplizerDefinition(node, EntityMode.Poco); + if (tuplizer != null) + { + string tupClassName = FullClassName(tuplizer.Attributes["class"].Value, mappings); + entity.AddTuplizer(EntityMode.Poco, tupClassName); + } + } + + private XmlNode LocateTuplizerDefinition(XmlNode container, EntityMode mode) + { + string modeToFind = EntityModeHelper.ToString(mode); + foreach (XmlNode node in container.SelectNodes(HbmConstants.nsTuplizer, namespaceManager)) + { + if (modeToFind.Equals(node.Attributes["entity-mode"].Value)) + return node; + } + return null; + } + private void BindJoin(XmlNode node, Join join) { PersistentClass persistentClass = join.PersistentClass; @@ -1116,27 +1177,20 @@ private static string GetEntityName(XmlNode elem, Mappings model) { - // TODO: H3.2 Implement real entityName (look at IEntityPersister for feature) - //string entityName = XmlHelper.GetAttributeValue(elem, "entity-name"); - //return entityName == null ? GetClassName( elem.Attributes[ "class" ], model ) : entityName; - XmlAttribute att = elem.Attributes["class"]; + string entityName = XmlHelper.GetAttributeValue(elem, "entity-name"); + if (entityName == null) + { + XmlAttribute att = elem.Attributes["class"]; - if (att == null) - return null; + return att == null ? null : GetClassName(att.Value, model); + } + else + { + return entityName; + } - return GetClassName(att.Value, model); } - private static string GetQualifiedClassName(XmlNode elem, Mappings model) - { - XmlAttribute att = elem.Attributes["class"]; - - if (att == null) - return null; - - return GetQualifiedClassName(att.Value, model); - } - protected XmlNodeList SelectNodes(XmlNode node, string xpath) { return node.SelectNodes(xpath, namespaceManager); Modified: trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/EmptyInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -58,7 +58,7 @@ return null; } - public string GetEntityName(object entity) + public virtual string GetEntityName(object entity) { return null; } Modified: trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Engine/UnsavedValueFactory.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -45,14 +45,11 @@ object defaultValue = identifierGetter.Get(Instantiate(constructor)); return new IdentifierValue(defaultValue); } - // TODO: NH - the branch below is actually never visited, so it's commented out - /* - else if( identifierGetter != null && ( identifierType is ValueTypeType ) ) + else if (identifierGetter != null && (identifierType is PrimitiveType)) { - object defaultValue = ( ( ValueTypeType ) identifierType ).DefaultValue; - return new Cascades.IdentifierValue( defaultValue ); + object defaultValue = ((PrimitiveType) identifierType).DefaultValue; + return new IdentifierValue(defaultValue); } - */ else { return IdentifierValue.SaveNull; Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -730,6 +730,7 @@ /// <returns></returns> public object Instantiate(IEntityPersister persister, object id) { + ErrorIfClosed(); object result = interceptor.Instantiate(persister.EntityName, entityMode, id); if (result == null) { Modified: trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Mapping/PersistentClass.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -59,7 +59,7 @@ private string temporaryIdTableName; private string temporaryIdTableDDL; - private IDictionary<EntityMode, System.Type> tuplizerImpls; + private IDictionary<EntityMode, string> tuplizerImpls; private Versioning.OptimisticLock optimisticLockMode; @@ -571,14 +571,11 @@ get { return temporaryIdTableDDL; } } - public virtual IDictionary<EntityMode, System.Type> TuplizerMap + public virtual IDictionary<EntityMode, string> TuplizerMap { get { - if (tuplizerImpls == null) - return null; - - return new Dictionary<EntityMode, System.Type>(tuplizerImpls); + return tuplizerImpls == null ? null : new UnmodifiableDictionary<EntityMode, string>(tuplizerImpls); } } @@ -1157,11 +1154,11 @@ get { return identifierMapper != null; } } - public void AddTuplizer(EntityMode entityMode, System.Type implClass) + public void AddTuplizer(EntityMode entityMode, string implClass) { if (tuplizerImpls == null) { - tuplizerImpls = new Dictionary<EntityMode, System.Type>(); + tuplizerImpls = new Dictionary<EntityMode, string>(); } tuplizerImpls[entityMode] = implClass; } @@ -1170,7 +1167,9 @@ { if (tuplizerImpls == null) return null; - return tuplizerImpls[mode].AssemblyQualifiedName; + string result; + tuplizerImpls.TryGetValue(mode, out result); + return result; } public bool HasNaturalId() Modified: trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Mapping/Subclass.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -161,19 +161,19 @@ get { return Superclass.FilterMap; } } - public override IDictionary<EntityMode, System.Type> TuplizerMap + public override IDictionary<EntityMode, string> TuplizerMap { get { - IDictionary<EntityMode, System.Type> specificTuplizerDefs = base.TuplizerMap; - IDictionary<EntityMode, System.Type> superclassTuplizerDefs = Superclass.TuplizerMap; + IDictionary<EntityMode, string> specificTuplizerDefs = base.TuplizerMap; + IDictionary<EntityMode, string> superclassTuplizerDefs = Superclass.TuplizerMap; if (specificTuplizerDefs == null && superclassTuplizerDefs == null) { return null; } else { - IDictionary<EntityMode, System.Type> combined = new Dictionary<EntityMode, System.Type>(); + IDictionary<EntityMode, string> combined = new Dictionary<EntityMode, string>(); if (superclassTuplizerDefs != null) { ArrayHelper.AddAll(combined, superclassTuplizerDefs); @@ -182,7 +182,7 @@ { ArrayHelper.AddAll(combined, specificTuplizerDefs); } - return combined; + return new UnmodifiableDictionary<EntityMode, string>(combined); } } } Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityEntityModeToTuplizerMapping.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using NHibernate.Mapping; +using NHibernate.Util; namespace NHibernate.Tuple.Entity { @@ -25,19 +26,14 @@ public EntityEntityModeToTuplizerMapping(PersistentClass mappedEntity, EntityMetamodel em) { // create our own copy of the user-supplied tuplizer impl map - Dictionary<EntityMode, System.Type> userSuppliedTuplizerImpls; - if (mappedEntity.TuplizerMap != null) - { - userSuppliedTuplizerImpls = new Dictionary<EntityMode, System.Type>(mappedEntity.TuplizerMap); - } - else - { - userSuppliedTuplizerImpls = new Dictionary<EntityMode, System.Type>(); - } + Dictionary<EntityMode, string> userSuppliedTuplizerImpls = mappedEntity.TuplizerMap != null + ? new Dictionary<EntityMode, string>( + mappedEntity.TuplizerMap) + : new Dictionary<EntityMode, string>(); // Build the dynamic-map tuplizer... ITuplizer dynamicMapTuplizer; - System.Type tuplizerImpl; + string tuplizerImpl; if (!userSuppliedTuplizerImpls.TryGetValue(EntityMode.Map, out tuplizerImpl)) { dynamicMapTuplizer = new DynamicMapEntityTuplizer(em, mappedEntity); @@ -51,7 +47,7 @@ // then the pojo tuplizer, using the dynamic-map tuplizer if no pojo representation is available ITuplizer pojoTuplizer; - System.Type tempObject2; + string tempObject2; userSuppliedTuplizerImpls.TryGetValue(EntityMode.Poco, out tempObject2); userSuppliedTuplizerImpls.Remove(EntityMode.Poco); tuplizerImpl = tempObject2; @@ -82,22 +78,23 @@ } // then handle any user-defined entity modes... - foreach (KeyValuePair<EntityMode, System.Type> pair in userSuppliedTuplizerImpls) + foreach (KeyValuePair<EntityMode, string> pair in userSuppliedTuplizerImpls) { IEntityTuplizer tuplizer = BuildEntityTuplizer(pair.Value, mappedEntity, em); AddTuplizer(pair.Key, tuplizer); } } - private static IEntityTuplizer BuildEntityTuplizer(System.Type implClass, PersistentClass pc, EntityMetamodel em) + private static IEntityTuplizer BuildEntityTuplizer(string className, PersistentClass pc, EntityMetamodel em) { try { + System.Type implClass = ReflectHelper.ClassForName(className); return (IEntityTuplizer)implClass.GetConstructor(entityTuplizerCTORSignature).Invoke(new object[] { em, pc }); } catch (Exception t) { - throw new HibernateException("Could not build tuplizer [" + implClass.FullName + "]", t); + throw new HibernateException("Could not build tuplizer [" + className + "]", t); } } Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Address.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,10 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Address + { + long Id { get; set;} + string Street { get; set;} + string City { get; set;} + string PostalCode { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Company.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,8 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Company + { + long Id { get; set;} + string Name { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Customer.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,7 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface Customer:Person + { + Company Company { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/DataProxyHandler.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,59 @@ +using System.Collections; +using Castle.Core.Interceptor; + +namespace NHibernate.Test.DynamicEntity +{ + public sealed class DataProxyHandler : Castle.Core.Interceptor.IInterceptor + { + private readonly Hashtable data = new Hashtable(); + private readonly string entityName; + + public DataProxyHandler(string entityName, object id) + { + this.entityName = entityName; + data["Id"] = id; + } + + public string EntityName + { + get { return entityName; } + } + + public Hashtable Data + { + get { return data; } + } + + #region IInterceptor Members + + public void Intercept(IInvocation invocation) + { + invocation.ReturnValue = null; + string methodName = invocation.Method.Name; + if ("get_DataHandler".Equals(methodName)) + { + invocation.ReturnValue = this; + } + else if (methodName.StartsWith("set_")) + { + string propertyName = methodName.Substring(4); + data[propertyName] = invocation.Arguments[0]; + } + else if (methodName.StartsWith("get_")) + { + string propertyName = methodName.Substring(4); + invocation.ReturnValue = data[propertyName]; + } + else if ("ToString".Equals(methodName)) + { + invocation.ReturnValue = entityName + "#" + data["Id"]; + } + else if ("GetHashCode".Equals(methodName)) + { + invocation.ReturnValue = GetHashCode(); + } + } + + #endregion + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/IProxyMarker.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,7 @@ +namespace NHibernate.Test.DynamicEntity +{ + public interface IProxyMarker + { + DataProxyHandler DataHandler { get;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/Customer.hbm.xml 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.DynamicEntity"> + + <!-- + Mapping the Customer and Company interfaces. Our custom Interceptor + will be responsible for: + a) creating instances representing these interfaces; + b) determining the appropriate entity-name (i.e., which entity mapping to use) given an instance of one of these proxies. + --> + <class name="Person" table="t_person" abstract="false"> + <!-- <class name="Person" table="t_person" discriminator-value="person"> --> + <id name="Id"> + <generator class="native"/> + </id> + <discriminator force="false"/> + <property name="Name"/> + + <many-to-one name="Address" cascade="all" column="addr_id"/> + + <set name="Family" lazy="true" cascade="all"> + <key column="pers_id"/> + <one-to-many class="Person"/> + </set> + + <subclass name="Customer" discriminator-value="customer" abstract="false"> + <many-to-one name="Company" cascade="none" column="comp_id"/> + </subclass> + </class> + + <!-- Company interface mapping --> + <class name="Company" table="t_company" abstract="false"> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Name"/> + </class> + + <class name="Address" table="t_address" abstract="false"> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Street"/> + <property name="City"/> + <property name="PostalCode"/> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/InterceptorDynamicEntity.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,92 @@ +using System.Collections; +using NHibernate.Cfg; +using NUnit.Framework; + +namespace NHibernate.Test.DynamicEntity.Interceptor +{ + [TestFixture] + public class InterceptorDynamicEntity : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"DynamicEntity.Interceptor.Customer.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + configuration.SetInterceptor(new ProxyInterceptor()); + } + + [Test] + public void It() + { + // Test saving these dyna-proxies + ISession session = OpenSession(); + session.BeginTransaction(); + Company company = ProxyHelper.NewCompanyProxy(); + company.Name = "acme"; + session.Save(company); + Customer customer = ProxyHelper.NewCustomerProxy(); + customer.Name = "Steve"; + customer.Company = company; + session.Save(customer); + session.Transaction.Commit(); + session.Close(); + + Assert.IsNotNull(company.Id, "company id not assigned"); + Assert.IsNotNull(customer.Id, "customer id not assigned"); + + // Test loading these dyna-proxies, along with flush processing + session = OpenSession(); + session.BeginTransaction(); + customer = session.Load<Customer>(customer.Id); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer), "should-be-proxy was initialized"); + + customer.Name = "other"; + session.Flush(); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Company), "should-be-proxy was initialized"); + + session.Refresh(customer); + Assert.AreEqual("other", customer.Name, "name not updated"); + Assert.AreEqual("acme", customer.Company.Name, "company association not correct"); + + session.Transaction.Commit(); + session.Close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.Name = "Steve"; + session = OpenSession(); + session.BeginTransaction(); + session.Update(customer); + session.Flush(); + session.Refresh(customer); + Assert.AreEqual("Steve", customer.Name, "name not updated"); + session.Transaction.Commit(); + session.Close(); + + // Test querying + session = OpenSession(); + session.BeginTransaction(); + int count = session.CreateQuery("from Customer").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Clear(); + count = session.CreateQuery("from Person").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Transaction.Commit(); + session.Close(); + + // test deleteing + session = OpenSession(); + session.BeginTransaction(); + session.Delete(company); + session.Delete(customer); + session.Transaction.Commit(); + session.Close(); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Interceptor/ProxyInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,27 @@ +namespace NHibernate.Test.DynamicEntity.Interceptor +{ + public class ProxyInterceptor : EmptyInterceptor + { + public override string GetEntityName(object entity) + { + string entityName = ProxyHelper.ExtractEntityName(entity) ?? base.GetEntityName(entity); + return entityName; + } + + public override object Instantiate(string entityName, EntityMode entityMode, object id) + { + if (entityMode == EntityMode.Poco) + { + if (typeof(Customer).FullName.Equals(entityName)) + { + return ProxyHelper.NewCustomerProxy(id); + } + else if (typeof(Company).FullName.Equals(entityName)) + { + return ProxyHelper.NewCompanyProxy(id); + } + } + return base.Instantiate(entityName, entityMode, id); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Person.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,12 @@ +using Iesi.Collections.Generic; + +namespace NHibernate.Test.DynamicEntity +{ + public interface Person + { + long Id { get; set;} + string Name { get; set;} + Address Address { get;set;} + ISet<Person> Family { get; set;} + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/ProxyHelper.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,79 @@ +using Castle.DynamicProxy; + +namespace NHibernate.Test.DynamicEntity +{ + public class ProxyHelper + { + private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator(); + + public static Person NewPersonProxy() + { + return NewPersonProxy(0L); + } + + public static Person NewPersonProxy(object id) + { + return + (Person) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Person), + new System.Type[] {typeof (IProxyMarker), typeof (Person)}, + new DataProxyHandler(typeof (Person).FullName, id)); + } + + public static Customer NewCustomerProxy() + { + return NewCustomerProxy(0L); + } + + public static Customer NewCustomerProxy(object id) + { + return + (Customer) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Customer), + new System.Type[] {typeof (IProxyMarker), typeof (Customer)}, + new DataProxyHandler(typeof (Customer).FullName, id)); + } + + public static Company NewCompanyProxy() + { + return NewCompanyProxy(0L); + } + + public static Company NewCompanyProxy(object id) + { + return + (Company) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Company), + new System.Type[] {typeof (IProxyMarker), typeof (Company)}, + new DataProxyHandler(typeof (Company).FullName, id)); + } + + public static Address NewAddressProxy() + { + return NewAddressProxy(0L); + } + + public static Address NewAddressProxy(object id) + { + return + (Address) + proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof (Address), + new System.Type[] {typeof (IProxyMarker), typeof (Address)}, + new DataProxyHandler(typeof (Address).FullName, id)); + } + + public static string ExtractEntityName(object obj) + { + // Our custom Proxy instances actually bundle + // their appropriate entity name, so we simply extract it from there + // if this represents one of our proxies; otherwise, we return null + IProxyMarker pm = obj as IProxyMarker; + if (pm != null) + { + DataProxyHandler myHandler = pm.DataHandler; + return myHandler.EntityName; + } + return null; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/Customer.hbm.xml 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8" ?> + +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.DynamicEntity"> + + <!-- + Mapping the Customer and Company interfaces. Our custom Interceptor + will be responsible for: + a) creating instances representing these interfaces; + b) determining the appropriate entity-name (i.e., which entity mapping to use) given an instance of one of these proxies. + --> + <class name="Person" table="t_person" discriminator-value="person" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <discriminator force="false"/> + <property name="Name"/> + + <many-to-one name="Address" cascade="all" column="addr_id"/> + + <set name="Family" lazy="true" cascade="all" generic="true"> + <key column="pers_id"/> + <one-to-many class="Person"/> + </set> + + <subclass name="Customer" discriminator-value="customer" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <many-to-one name="Company" cascade="none" column="comp_id"/> + </subclass> + </class> + + <!-- Company interface mapping --> + <class name="Company" table="t_company" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Name"/> + </class> + + <class name="Address" table="t_address" abstract="false"> + <tuplizer class="NHibernate.Test.DynamicEntity.Tuplizer.MyEntityTuplizer, NHibernate.Test" entity-mode="poco"/> + <id name="Id"> + <generator class="native"/> + </id> + <property name="Street"/> + <property name="City"/> + <property name="PostalCode"/> + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/EntityNameInterceptor.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,11 @@ +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class EntityNameInterceptor : EmptyInterceptor + { + public override string GetEntityName(object entity) + { + string entityName = ProxyHelper.ExtractEntityName(entity) ?? base.GetEntityName(entity); + return entityName; + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityInstantiator.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,56 @@ +using System; +using NHibernate.Tuple; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class MyEntityInstantiator : IInstantiator + { + private readonly System.Type entityType; + + public MyEntityInstantiator(System.Type entityType) + { + this.entityType = entityType; + } + + public object Instantiate(object id) + { + if (typeof(Person).Equals(entityType)) + { + return ProxyHelper.NewPersonProxy(id); + } + if (typeof(Customer).Equals(entityType)) + { + return ProxyHelper.NewCustomerProxy(id); + } + else if (typeof(Company).Equals(entityType)) + { + return ProxyHelper.NewCompanyProxy(id); + } + else if (typeof(Address).Equals(entityType)) + { + return ProxyHelper.NewAddressProxy(id); + } + else + { + throw new ArgumentException("unknown entity for instantiation [" + entityType.FullName + "]"); + } + } + + public object Instantiate() + { + return Instantiate(null); + } + + public bool IsInstance(object obj) + { + try + { + return entityType.IsInstanceOfType(obj); + } + catch (Exception e) + { + throw new HibernateException("could not get handle to entity-name as interface : " + e); + } + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/MyEntityTuplizer.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,24 @@ +using NHibernate.Mapping; +using NHibernate.Tuple.Entity; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + public class MyEntityTuplizer : PocoEntityTuplizer + { + public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) : base(entityMetamodel, mappedEntity) {} + + protected override Tuple.IInstantiator BuildInstantiator(PersistentClass persistentClass) + { + return new MyEntityInstantiator(persistentClass.MappedClass); + } + + protected override Proxy.IProxyFactory BuildProxyFactory(PersistentClass persistentClass, NHibernate.Properties.IGetter idGetter, NHibernate.Properties.ISetter idSetter) + { + // allows defining a custom proxy factory, which is responsible for + // generating lazy proxies for a given entity. + // + // Here we simply use the default... + return base.BuildProxyFactory(persistentClass, idGetter, idSetter); + } + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/DynamicEntity/Tuplizer/TuplizerDynamicEntity.cs 2008-07-21 04:49:58 UTC (rev 3642) @@ -0,0 +1,108 @@ +using System.Collections; +using Iesi.Collections.Generic; +using NHibernate.Cfg; +using NUnit.Framework; + +namespace NHibernate.Test.DynamicEntity.Tuplizer +{ + [TestFixture] + public class TuplizerDynamicEntity : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new string[] {"DynamicEntity.Tuplizer.Customer.hbm.xml"}; } + } + + protected override void Configure(Configuration configuration) + { + configuration.SetInterceptor(new EntityNameInterceptor()); + } + + [Test] + public void It() + { + // Test saving these dyna-proxies + ISession session = OpenSession(); + session.BeginTransaction(); + Company company = ProxyHelper.NewCompanyProxy(); + company.Name = "acme"; + session.Save(company); + Customer customer = ProxyHelper.NewCustomerProxy(); + customer.Name = "Steve"; + customer.Company = company; + Address address = ProxyHelper.NewAddressProxy(); + address.Street = "somewhere over the rainbow"; + address.City = "lawerence, kansas"; + address.PostalCode = "toto"; + customer.Address = address; + customer.Family = new HashedSet<Person>(); + Person son = ProxyHelper.NewPersonProxy(); + son.Name = "son"; + customer.Family.Add(son); + Person wife = ProxyHelper.NewPersonProxy(); + wife.Name = "wife"; + customer.Family.Add(wife); + session.Save(customer); + session.Transaction.Commit(); + session.Close(); + + Assert.IsNotNull(company.Id, "company id not assigned"); + Assert.IsNotNull(customer.Id, "customer id not assigned"); + Assert.IsNotNull(address.Id, "address id not assigned"); + Assert.IsNotNull(son.Id, "son:Person id not assigned"); + Assert.IsNotNull(wife.Id, "wife:Person id not assigned"); + + // Test loading these dyna-proxies, along with flush processing + session = OpenSession(); + session.BeginTransaction(); + customer = session.Load<Customer>(customer.Id); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer), "should-be-proxy was initialized"); + + customer.Name = "other"; + session.Flush(); + Assert.IsFalse(NHibernateUtil.IsInitialized(customer.Company), "should-be-proxy was initialized"); + + session.Refresh(customer); + Assert.AreEqual("other", customer.Name, "name not updated"); + Assert.AreEqual("acme", customer.Company.Name, "company association not correct"); + + session.Transaction.Commit(); + session.Close(); + + // Test detached entity re-attachment with these dyna-proxies + customer.Name = "Steve"; + session = OpenSession(); + session.BeginTransaction(); + session.Update(customer); + session.Flush(); + session.Refresh(customer); + Assert.AreEqual("Steve", customer.Name, "name not updated"); + session.Transaction.Commit(); + session.Close(); + + // Test querying + session = OpenSession(); + session.BeginTransaction(); + int count = session.CreateQuery("from Customer").List().Count; + Assert.AreEqual(1, count, "querying dynamic entity"); + session.Clear(); + count = session.CreateQuery("from Person").List().Count; + Assert.AreEqual(3, count, "querying dynamic entity"); + session.Transaction.Commit(); + session.Close(); + + // test deleteing + session = OpenSession(); + session.BeginTransaction(); + session.Delete(company); + session.Delete(customer); + session.Transaction.Commit(); + session.Close(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-19 14:07:03 UTC (rev 3641) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj 2008-07-21 04:49:58 UTC (rev 3642) @@ -120,6 +120,19 @@ <Compile Include="DriverTest\NullReferenceFixture.cs" /> <Compile Include="DriverTest\OracleClientDriverFixture.cs" /> <Compile Include="DriverTest\OracleDataClientDriverFixture.cs" /> + <Compile Include="DynamicEntity\Address.cs" /> + <Compile Include="DynamicEntity\Company.cs" /> + <Compile Include="DynamicEntity\Customer.cs" /> + <Compile Include="DynamicEntity\DataProxyHandler.cs" /> + <Compile Include="DynamicEntity\Interceptor\InterceptorDynamicEntity.cs" /> + <Compile Include="DynamicEntity\Interceptor\ProxyInterceptor.cs" /> + <Compile Include="DynamicEntity\IProxyMarker.cs" /> + <Compile Include="DynamicEntity\Person.cs" /> + <Compile Include="DynamicEntity\ProxyHelper.cs" /> + <Compile Include="DynamicEntity\Tuplizer\EntityNameInterceptor.cs" /> + <Compile Include="DynamicEntity\Tuplizer\MyEntityInstantiator.cs" /> + <Compile Include="DynamicEntity\Tuplizer\MyEntityTuplizer.cs" /> + <Compile Include="DynamicEntity\Tuplizer\TuplizerDynamicEntity.cs" /> <Compile Include="EngineTest\TypedValueFixture.cs" /> <Compile Include="ExceptionsTest\Group.cs" /> <Compile Include="ExceptionsTest\MSSQLExceptionConverterExample.cs" /> @@ -1345,6 +1358,11 @@ <EmbeddedResource Include="NHSpecificTest\NH1291AnonExample\Mappings.hbm.xml" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="DynamicEntity\Interceptor\Customer.hbm.xml" /> + <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="DynamicEntity\Tuplizer\Customer.hbm.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="Properties\" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |