From: <aye...@us...> - 2010-01-24 21:46:57
|
Revision: 4925 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4925&view=rev Author: ayenderahien Date: 2010-01-24 21:46:35 +0000 (Sun, 24 Jan 2010) Log Message: ----------- adding support for ghost properties Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmManyToOne.cs trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs trunk/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs trunk/nhibernate/src/NHibernate/Intercept/AbstractFieldInterceptor.cs trunk/nhibernate/src/NHibernate/Intercept/DefaultFieldInterceptor.cs trunk/nhibernate/src/NHibernate/Intercept/FieldInterceptionHelper.cs trunk/nhibernate/src/NHibernate/Intercept/IFieldInterceptor.cs trunk/nhibernate/src/NHibernate/Mapping/Property.cs trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs trunk/nhibernate/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs trunk/nhibernate/src/NHibernate/nhibernate-mapping.xsd trunk/nhibernate/src/NHibernate.ByteCode.Castle/LazyFieldInterceptor.cs trunk/nhibernate/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/GhostProperty/ trunk/nhibernate/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs trunk/nhibernate/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/GhostProperty/Order.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/Hbm.generated.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -672,11 +672,19 @@ /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute("not-null")] public bool notnull; - + /// <remarks/> [System.Xml.Serialization.XmlIgnoreAttribute()] public bool notnullSpecified; - + + /// <remarks/> + [System.Xml.Serialization.XmlAttributeAttribute("force-load-on-property-access")] + public bool forceloadonpropertyaccess; + + /// <remarks/> + [System.Xml.Serialization.XmlAttributeAttribute()] + public bool forceloadonpropertyaccessSpecified; + /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] [System.ComponentModel.DefaultValueAttribute(false)] Modified: trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmManyToOne.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmManyToOne.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Cfg/MappingSchema/HbmManyToOne.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -28,6 +28,11 @@ get { return optimisticlock; } } + public bool ForceLoadOnPropertyAccess + { + get { return forceloadonpropertyaccess; } + } + #endregion #region Overrides of AbstractDecoratable Modified: trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Cfg/XmlHbmBinding/PropertiesBinder.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -107,6 +107,7 @@ var value = new ManyToOne(table); BindManyToOne(manyToOneMapping, value, propertyName, true); property = CreateProperty(entityPropertyMapping, className, value, inheritedMetas); + property.IsGhostProperty = manyToOneMapping.ForceLoadOnPropertyAccess; BindManyToOneProperty(manyToOneMapping, property); } else if ((componentMapping = entityPropertyMapping as HbmComponent) != null) Modified: trunk/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Event/Default/AbstractSaveEventListener.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -292,7 +292,7 @@ { if (FieldInterceptionHelper.IsInstrumented(entity)) { - IFieldInterceptor interceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, persister.EntityName, null, source); + IFieldInterceptor interceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, persister.EntityName, null, null, source); interceptor.MarkDirty(); } } Modified: trunk/nhibernate/src/NHibernate/Intercept/AbstractFieldInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Intercept/AbstractFieldInterceptor.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Intercept/AbstractFieldInterceptor.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -1,6 +1,7 @@ using System; using Iesi.Collections.Generic; using NHibernate.Engine; +using NHibernate.Proxy; namespace NHibernate.Intercept { @@ -12,16 +13,18 @@ [NonSerialized] private ISessionImplementor session; private ISet<string> uninitializedFields; + private ISet<string> uninitializedGhostFieldNames; private readonly string entityName; [NonSerialized] private bool initializing; private bool isDirty; - protected internal AbstractFieldInterceptor(ISessionImplementor session, ISet<string> uninitializedFields, string entityName) + protected internal AbstractFieldInterceptor(ISessionImplementor session, ISet<string> uninitializedFields, ISet<string> uninitializedGhostFieldNames, string entityName) { this.session = session; this.uninitializedFields = uninitializedFields; + this.uninitializedGhostFieldNames = uninitializedGhostFieldNames; this.entityName = entityName; } @@ -74,11 +77,9 @@ get { return initializing; } } - public object Intercept(object target, string fieldName) + public object Intercept(object target, string fieldName, object value) { - if (initializing || - uninitializedFields == null || - !uninitializedFields.Contains(fieldName)) + if (initializing) return InvokeImplementation; if (session == null) @@ -90,11 +91,38 @@ throw new LazyInitializationException("session is not connected"); } + if (uninitializedFields != null && uninitializedFields.Contains(fieldName)) + { + return InitializeField(fieldName, target); + } + if (value is INHibernateProxy && uninitializedGhostFieldNames != null && uninitializedGhostFieldNames.Contains(fieldName)) + { + return InitializeOrGetAssociation((INHibernateProxy)value); + } + return InvokeImplementation; + } + + private object InitializeOrGetAssociation(INHibernateProxy value) + { + if(value.HibernateLazyInitializer.IsUninitialized) + { + value.HibernateLazyInitializer.Initialize(); + var association = value.HibernateLazyInitializer.GetImplementation(session); + var narrowedProxy = session.PersistenceContext.ProxyFor(association); + // we set the narrowed impl here to be able to get it back in the future + value.HibernateLazyInitializer.SetImplementation(narrowedProxy); + } + return value.HibernateLazyInitializer.GetImplementation(session); + } + + private object InitializeField(string fieldName, object target) + { object result; initializing = true; try { - result = ((ILazyPropertyInitializer)session.Factory.GetEntityPersister(entityName)).InitializeLazyProperty(fieldName, target, session); + var lazyPropertyInitializer = ((ILazyPropertyInitializer) session.Factory.GetEntityPersister(entityName)); + result = lazyPropertyInitializer.InitializeLazyProperty(fieldName, target, session); } finally { Modified: trunk/nhibernate/src/NHibernate/Intercept/DefaultFieldInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Intercept/DefaultFieldInterceptor.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Intercept/DefaultFieldInterceptor.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -5,8 +5,8 @@ { public class DefaultFieldInterceptor : AbstractFieldInterceptor { - public DefaultFieldInterceptor(ISessionImplementor session, ISet<string> uninitializedFields, string entityName) - : base(session, uninitializedFields, entityName) + public DefaultFieldInterceptor(ISessionImplementor session, ISet<string> uninitializedFields, ISet<string> uninitializedGhostFieldNames, string entityName) + : base(session, uninitializedFields, uninitializedGhostFieldNames, entityName) { } } Modified: trunk/nhibernate/src/NHibernate/Intercept/FieldInterceptionHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Intercept/FieldInterceptionHelper.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Intercept/FieldInterceptionHelper.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -32,12 +32,15 @@ return fieldInterceptorAccessor == null ? null : fieldInterceptorAccessor.FieldInterceptor; } - public static IFieldInterceptor InjectFieldInterceptor(object entity, string entityName, ISet<string> uninitializedFieldNames, ISessionImplementor session) + public static IFieldInterceptor InjectFieldInterceptor(object entity, string entityName, + ISet<string> uninitializedFieldNames, + ISet<string> uninitializedGhostFieldNames, + ISessionImplementor session) { var fieldInterceptorAccessor = entity as IFieldInterceptorAccessor; if (fieldInterceptorAccessor != null) { - var fieldInterceptorImpl = new DefaultFieldInterceptor(session, uninitializedFieldNames, entityName); + var fieldInterceptorImpl = new DefaultFieldInterceptor(session, uninitializedFieldNames, uninitializedGhostFieldNames, entityName); fieldInterceptorAccessor.FieldInterceptor = fieldInterceptorImpl; return fieldInterceptorImpl; } Modified: trunk/nhibernate/src/NHibernate/Intercept/IFieldInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Intercept/IFieldInterceptor.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Intercept/IFieldInterceptor.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -28,6 +28,6 @@ void ClearDirty(); /// <summary> Intercept field set/get </summary> - object Intercept(object target, string fieldName); + object Intercept(object target, string fieldName, object value); } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Mapping/Property.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/Property.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Mapping/Property.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -132,10 +132,10 @@ { bool[] columnUpdateability = propertyValue.ColumnUpdateability; return updateable && - ( - // columnUpdateability.Length == 0 || - !ArrayHelper.IsAllFalse(columnUpdateability) - ); + ( + // columnUpdateability.Length == 0 || + !ArrayHelper.IsAllFalse(columnUpdateability) + ); } set { updateable = value; } } @@ -146,10 +146,10 @@ { bool[] columnInsertability = propertyValue.ColumnInsertability; return insertable && - ( - columnInsertability.Length == 0 || - !ArrayHelper.IsAllFalse(columnInsertability) - ); + ( + columnInsertability.Length == 0 || + !ArrayHelper.IsAllFalse(columnInsertability) + ); } set { insertable = value; } } @@ -206,7 +206,7 @@ public MetaAttribute GetMetaAttribute(string attributeName) { - if(metaAttributes == null) + if (metaAttributes == null) { return null; } @@ -226,7 +226,7 @@ { if (propertyValue is SimpleValue) { - return ((SimpleValue) propertyValue).NullValue; + return ((SimpleValue)propertyValue).NullValue; } else return null; @@ -304,5 +304,7 @@ get { return nodeName; } set { nodeName = value; } } + + public bool IsGhostProperty { get; set; } } } Modified: trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -3615,7 +3615,7 @@ } else { - IFieldInterceptor fieldInterceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, null, session); + IFieldInterceptor fieldInterceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, null, null, session); fieldInterceptor.MarkDirty(); } } Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/EntityMetamodel.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -153,6 +153,11 @@ { hasLazy = true; } + if (prop.IsGhostProperty) + { + hasGhostProperties = true; + } + propertyLaziness[i] = lazyProperty; propertyNames[i] = properties[i].Name; @@ -230,20 +235,23 @@ else { log.Info("lazy property fetching available for: " + name); - foreach (var prop in persistentClass.PropertyClosureIterator) - { - if (prop.IsLazy == false) - continue; - - var getter = prop.GetGetter(persistentClass.MappedClass); - if(getter.Method == null || - getter.Method.IsDefined(typeof(CompilerGeneratedAttribute), false) == false) - { - log.ErrorFormat("Lazy property {0}.{1} is not an auto property, which may result in uninitialized property access", persistentClass.EntityName, prop.Name); - } - } + VerifyCanInterceptPropertiesForLazyOrGhostProperties(persistentClass); } } + if(hasGhostProperties) + { + if (lazy == false) + { + log.WarnFormat("Disabled ghost properies fetching for {0} beacuse it does not support lazy at the entity level", name); + hasGhostProperties = false; + } + else + { + log.Info("Ghost property fetching available for: " + name); + if (hasLazy == false) // avoid double checking + VerifyCanInterceptPropertiesForLazyOrGhostProperties(persistentClass); + } + } mutable = persistentClass.IsMutable; @@ -291,6 +299,22 @@ tuplizerMapping = new EntityEntityModeToTuplizerMapping(persistentClass, this); } + private static void VerifyCanInterceptPropertiesForLazyOrGhostProperties(PersistentClass persistentClass) + { + foreach (var prop in persistentClass.PropertyClosureIterator) + { + if (prop.IsLazy == false && prop.IsGhostProperty) + continue; + + var getter = prop.GetGetter(persistentClass.MappedClass); + if(getter.Method == null || + getter.Method.IsDefined(typeof(CompilerGeneratedAttribute), false) == false) + { + log.ErrorFormat("Lazy or ghost property {0}.{1} is not an auto property, which may result in uninitialized property access", persistentClass.EntityName, prop.Name); + } + } + } + private ValueInclusion DetermineInsertValueGenerationType(Mapping.Property mappingProperty, StandardProperty runtimeProperty) { if (runtimeProperty.IsInsertGenerated) @@ -659,6 +683,7 @@ #region Tuplizer private readonly EntityEntityModeToTuplizerMapping tuplizerMapping; + private bool hasGhostProperties; public IEntityTuplizer GetTuplizer(EntityMode entityMode) { @@ -681,6 +706,11 @@ get { return naturalIdPropertyNumbers != null; } } + public bool HasGhostProperties + { + get { return hasGhostProperties; } + } + public bool HasNonIdentifierPropertyNamedId { get { return hasNonIdentifierPropertyNamedId; } Modified: trunk/nhibernate/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -25,6 +25,7 @@ private readonly bool islifecycleImplementor; private readonly bool isValidatableImplementor; private readonly HashedSet<string> lazyPropertyNames = new HashedSet<string>(); + private readonly HashedSet<string> ghostPropertyNames = new HashedSet<string>(); [NonSerialized] private IReflectionOptimizer optimizer; private readonly IProxyValidator proxyValidator; @@ -54,6 +55,8 @@ { if (property.IsLazy) lazyPropertyNames.Add(property.Name); + if (property.IsGhostProperty) + ghostPropertyNames.Add(property.Name); } SetReflectionOptimizer(); @@ -74,10 +77,10 @@ public override bool IsInstrumented { - get { - return - EntityMetamodel.HasLazyProperties && - FieldInterceptionHelper.IsInstrumented(MappedClass); + get + { + return (EntityMetamodel.HasLazyProperties || EntityMetamodel.HasGhostProperties) + && FieldInterceptionHelper.IsInstrumented(MappedClass); } } @@ -101,12 +104,12 @@ if (optimizer == null) { log.Debug("Create Instantiator without optimizer for:" + persistentClass.MappedClass.FullName); - return new PocoInstantiator(persistentClass, null, ProxyFactory, EntityMetamodel.HasLazyProperties); + return new PocoInstantiator(persistentClass, null, ProxyFactory, EntityMetamodel.HasLazyProperties || EntityMetamodel.HasGhostProperties); } else { log.Debug("Create Instantiator using optimizer for:" + persistentClass.MappedClass.FullName); - return new PocoInstantiator(persistentClass, optimizer.InstantiationOptimizer, ProxyFactory, EntityMetamodel.HasLazyProperties); + return new PocoInstantiator(persistentClass, optimizer.InstantiationOptimizer, ProxyFactory, EntityMetamodel.HasLazyProperties || EntityMetamodel.HasGhostProperties); } } @@ -226,7 +229,7 @@ HashedSet<string> lazyProps = lazyPropertiesAreUnfetched && EntityMetamodel.HasLazyProperties ? lazyPropertyNames : null; //TODO: if we support multiple fetch groups, we would need // to clone the set of lazy properties! - FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, lazyProps, session); + FieldInterceptionHelper.InjectFieldInterceptor(entity, EntityName, lazyProps, ghostPropertyNames, session); } } Modified: trunk/nhibernate/src/NHibernate/nhibernate-mapping.xsd =================================================================== --- trunk/nhibernate/src/NHibernate/nhibernate-mapping.xsd 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate/nhibernate-mapping.xsd 2010-01-24 21:46:35 UTC (rev 4925) @@ -879,6 +879,8 @@ </xs:attribute> <xs:attribute name="unique" default="false" type="xs:boolean"> </xs:attribute> + <xs:attribute name="force-load-on-property-access" default="false" type="xs:boolean"> + </xs:attribute> <xs:attribute name="unique-key" type="xs:string" /> <xs:attribute name="index" type="xs:string" /> <xs:attribute name="cascade" type="xs:string" /> Modified: trunk/nhibernate/src/NHibernate.ByteCode.Castle/LazyFieldInterceptor.cs =================================================================== --- trunk/nhibernate/src/NHibernate.ByteCode.Castle/LazyFieldInterceptor.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate.ByteCode.Castle/LazyFieldInterceptor.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -18,20 +18,22 @@ { if (ReflectHelper.IsPropertyGet(invocation.Method)) { - var result = FieldInterceptor.Intercept(invocation.InvocationTarget, ReflectHelper.GetPropertyName(invocation.Method)); - if (result == AbstractFieldInterceptor.InvokeImplementation) + invocation.Proceed(); // get the existing value + + var result = FieldInterceptor.Intercept( + invocation.InvocationTarget, + ReflectHelper.GetPropertyName(invocation.Method), + invocation.ReturnValue); + + if (result != AbstractFieldInterceptor.InvokeImplementation) { - invocation.Proceed(); - } - else - { invocation.ReturnValue = result; } } else if (ReflectHelper.IsPropertySet(invocation.Method)) { FieldInterceptor.MarkDirty(); - FieldInterceptor.Intercept(invocation.InvocationTarget, ReflectHelper.GetPropertyName(invocation.Method)); + FieldInterceptor.Intercept(invocation.InvocationTarget, ReflectHelper.GetPropertyName(invocation.Method), null); invocation.Proceed(); } } Property changes on: trunk/nhibernate/src/NHibernate.Test/GhostProperty ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Added: trunk/nhibernate/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -0,0 +1,81 @@ +using System.Collections; +using NHibernate.ByteCode.Castle; +using NHibernate.Cfg; +using NUnit.Framework; + +namespace NHibernate.Test.GhostProperty +{ + [TestFixture] + public class GhostPropertyFixture : TestCase + { + protected override string MappingsAssembly + { + get { return "NHibernate.Test"; } + } + + protected override IList Mappings + { + get { return new[] { "GhostProperty.Mappings.hbm.xml" }; } + } + + protected override void Configure(NHibernate.Cfg.Configuration configuration) + { + configuration.SetProperty(Environment.ProxyFactoryFactoryClass, + typeof(ProxyFactoryFactory).AssemblyQualifiedName); + } + + protected override void OnSetUp() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + var wireTransfer = new WireTransfer + { + Id = 1 + }; + s.Persist(wireTransfer); + s.Persist(new Order + { + Id = 1, + Payment = wireTransfer + }); + tx.Commit(); + } + + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + s.Delete("from Order"); + s.Delete("from Payment"); + tx.Commit(); + } + } + + [Test] + public void CanGetActualValueFromLazyManyToOne() + { + using (ISession s = OpenSession()) + { + var order = s.Get<Order>(1); + + Assert.IsTrue(order.Payment is WireTransfer); + } + } + + [Test] + public void GhostPropertyMaintainIdentityMap() + { + using (ISession s = OpenSession()) + { + var order = s.Get<Order>(1); + + Assert.AreSame(order.Payment, s.Load<Payment>(1)); + } + } + + } +} \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml 2010-01-24 21:46:35 UTC (rev 4925) @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" + assembly="NHibernate.Test" + namespace="NHibernate.Test.GhostProperty"> + + <class name="Order" table="Orders"> + <id name="Id"> + <generator class="assigned" /> + </id> + <many-to-one name="Payment" force-load-on-property-access="true"/> + </class> + + + <class name="Payment" abstract="true"> + <id name="Id"> + <generator class="assigned" /> + </id> + <discriminator column="Type" type="System.String"/> + <subclass name="WireTransfer" discriminator-value="WT"> + + </subclass> + <subclass name="CreditCard" discriminator-value="CC"> + + </subclass> + + </class> + +</hibernate-mapping> Added: trunk/nhibernate/src/NHibernate.Test/GhostProperty/Order.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/GhostProperty/Order.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/GhostProperty/Order.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -0,0 +1,16 @@ +namespace NHibernate.Test.GhostProperty +{ + public class Order + { + public virtual int Id { get; set; } + public virtual Payment Payment { get; set; } + } + + public abstract class Payment + { + public virtual int Id { get; set; } + } + + public class WireTransfer : Payment{} + public class CreditCard : Payment { } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs 2010-01-24 21:46:35 UTC (rev 4925) @@ -85,7 +85,7 @@ [Test] public void ShouldGenerateErrorForNonAutoPropLazyProp() { - Assert.IsTrue(log.Contains("Lazy property NHibernate.Test.LazyProperty.Book.ALotOfText is not an auto property, which may result in uninitialized property access")); + Assert.IsTrue(log.Contains("Lazy or ghost property NHibernate.Test.LazyProperty.Book.ALotOfText is not an auto property, which may result in uninitialized property access")); } [Test] Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-01-24 17:41:59 UTC (rev 4924) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2010-01-24 21:46:35 UTC (rev 4925) @@ -341,6 +341,8 @@ <Compile Include="GenericTest\SetGeneric\A.cs" /> <Compile Include="GenericTest\SetGeneric\B.cs" /> <Compile Include="GenericTest\SetGeneric\SetGenericFixture.cs" /> + <Compile Include="GhostProperty\Order.cs" /> + <Compile Include="GhostProperty\GhostPropertyFixture.cs" /> <Compile Include="HQL\Animal.cs" /> <Compile Include="HQL\Ast\Address.cs" /> <Compile Include="HQL\Ast\Animal.cs" /> @@ -2113,6 +2115,7 @@ <EmbeddedResource Include="CfgTest\Loquacious\EntityToCache.hbm.xml" /> <EmbeddedResource Include="DriverTest\SqlServerCeEntity.hbm.xml" /> <Content Include="DynamicEntity\package.html" /> + <EmbeddedResource Include="GhostProperty\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2065\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH2009\Mappings.hbm.xml" /> <EmbeddedResource Include="NHSpecificTest\NH1989\Mappings.hbm.xml" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |