You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(248) |
May
(82) |
Jun
(90) |
Jul
(177) |
Aug
(253) |
Sep
(157) |
Oct
(151) |
Nov
(143) |
Dec
(278) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(152) |
Feb
(107) |
Mar
(177) |
Apr
(133) |
May
(259) |
Jun
(81) |
Jul
(119) |
Aug
(306) |
Sep
(416) |
Oct
(240) |
Nov
(329) |
Dec
(206) |
2006 |
Jan
(466) |
Feb
(382) |
Mar
(153) |
Apr
(162) |
May
(133) |
Jun
(21) |
Jul
(18) |
Aug
(37) |
Sep
(97) |
Oct
(114) |
Nov
(110) |
Dec
(28) |
2007 |
Jan
(74) |
Feb
(65) |
Mar
(49) |
Apr
(76) |
May
(43) |
Jun
(15) |
Jul
(68) |
Aug
(55) |
Sep
(63) |
Oct
(59) |
Nov
(70) |
Dec
(66) |
2008 |
Jan
(71) |
Feb
(60) |
Mar
(120) |
Apr
(31) |
May
(48) |
Jun
(81) |
Jul
(107) |
Aug
(51) |
Sep
(80) |
Oct
(83) |
Nov
(83) |
Dec
(79) |
2009 |
Jan
(83) |
Feb
(110) |
Mar
(97) |
Apr
(91) |
May
(291) |
Jun
(250) |
Jul
(197) |
Aug
(58) |
Sep
(54) |
Oct
(122) |
Nov
(68) |
Dec
(34) |
2010 |
Jan
(50) |
Feb
(17) |
Mar
(63) |
Apr
(61) |
May
(84) |
Jun
(81) |
Jul
(138) |
Aug
(144) |
Sep
(78) |
Oct
(26) |
Nov
(30) |
Dec
(61) |
2011 |
Jan
(33) |
Feb
(35) |
Mar
(166) |
Apr
(221) |
May
(109) |
Jun
(76) |
Jul
(27) |
Aug
(37) |
Sep
(1) |
Oct
(4) |
Nov
(2) |
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
(2) |
Apr
(2) |
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2013 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
(1) |
Sep
(3) |
Oct
(2) |
Nov
|
Dec
(1) |
2014 |
Jan
(1) |
Feb
(1) |
Mar
(3) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <fab...@us...> - 2011-04-20 21:27:39
|
Revision: 5728 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5728&view=rev Author: fabiomaulo Date: 2011-04-20 21:27:33 +0000 (Wed, 20 Apr 2011) Log Message: ----------- Refactoring (+ fix wrong test) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/AbstractPropertyContainerMapperTest.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs 2011-04-20 20:50:46 UTC (rev 5727) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs 2011-04-20 21:27:33 UTC (rev 5728) @@ -37,7 +37,7 @@ public virtual void Property(MemberInfo property, Action<IPropertyMapper> mapping) { - if (!property.DeclaringType.IsAssignableFrom(container)) + if (!IsMemberSupportedByMappedContainer(property)) { throw new ArgumentOutOfRangeException("property", "Can't add a property of another graph"); } @@ -46,28 +46,49 @@ AddProperty(hbmProperty); } + protected virtual bool IsMemberSupportedByMappedContainer(MemberInfo property) + { + return property.DeclaringType.IsAssignableFrom(container); + } + public virtual void Component(MemberInfo property, Action<IComponentMapper> mapping) { - var hbm = new HbmComponent {name = property.Name}; + if (!IsMemberSupportedByMappedContainer(property)) + { + throw new ArgumentOutOfRangeException("property", "Can't add a property of another graph"); + } + var hbm = new HbmComponent { name = property.Name }; mapping(new ComponentMapper(hbm, property.GetPropertyOrFieldType(), property, MapDoc)); AddProperty(hbm); } public virtual void Component(MemberInfo property, Action<IDynamicComponentMapper> mapping) { + if (!IsMemberSupportedByMappedContainer(property)) + { + throw new ArgumentOutOfRangeException("property", "Can't add a property of another graph"); + } throw new NotImplementedException(); } public virtual void ManyToOne(MemberInfo property, Action<IManyToOneMapper> mapping) { - var hbm = new HbmManyToOne {name = property.Name}; + if (!IsMemberSupportedByMappedContainer(property)) + { + throw new ArgumentOutOfRangeException("property", "Can't add a property of another graph"); + } + var hbm = new HbmManyToOne { name = property.Name }; mapping(new ManyToOneMapper(property, hbm, MapDoc)); AddProperty(hbm); } public void Any(MemberInfo property, System.Type idTypeOfMetaType, Action<IAnyMapper> mapping) { - var hbm = new HbmAny {name = property.Name}; + if (!IsMemberSupportedByMappedContainer(property)) + { + throw new ArgumentOutOfRangeException("property", "Can't add a property of another graph"); + } + var hbm = new HbmAny { name = property.Name }; mapping(new AnyMapper(property, idTypeOfMetaType, hbm, MapDoc)); AddProperty(hbm); } Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/AbstractPropertyContainerMapperTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/AbstractPropertyContainerMapperTest.cs 2011-04-20 20:50:46 UTC (rev 5727) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/AbstractPropertyContainerMapperTest.cs 2011-04-20 21:27:33 UTC (rev 5728) @@ -88,7 +88,7 @@ public void CallAnyMapper() { var properties = new List<object>(); - var map = new StubPropertyContainerMapper<EntitySimple>(properties); + var map = new StubPropertyContainerMapper<MyClass>(properties); var called = false; map.Any(typeof(MyClass).GetProperty("Reference"), typeof(int), x => called = true); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-20 20:50:52
|
Revision: 5727 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5727&view=rev Author: fabiomaulo Date: 2011-04-20 20:50:46 +0000 (Wed, 20 Apr 2011) Log Message: ----------- making the XmlSerializer static to gain performance (at least for our tests) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs Modified: trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2011-04-20 20:31:21 UTC (rev 5726) +++ trunk/nhibernate/src/NHibernate/Cfg/Configuration.cs 2011-04-20 20:50:46 UTC (rev 5727) @@ -81,7 +81,7 @@ protected internal SettingsFactory settingsFactory; - private readonly XmlSerializer mappingDocumentSerializer = new XmlSerializer(typeof(HbmMapping)); + private static readonly XmlSerializer mappingDocumentSerializer = new XmlSerializer(typeof(HbmMapping)); #region ISerializable Members public Configuration(SerializationInfo info, StreamingContext context) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-20 20:31:28
|
Revision: 5726 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5726&view=rev Author: fabiomaulo Date: 2011-04-20 20:31:21 +0000 (Wed, 20 Apr 2011) Log Message: ----------- Add property to dyn-comp Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs 2011-04-20 19:28:30 UTC (rev 5725) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs 2011-04-20 20:31:21 UTC (rev 5726) @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using NHibernate.Cfg.MappingSchema; @@ -7,17 +8,24 @@ public class DynamicComponentMapper : IDynamicComponentMapper { private readonly HbmDynamicComponent component; + private readonly HbmMapping mapDoc; private readonly IAccessorPropertyMapper accessorPropertyMapper; public DynamicComponentMapper(HbmDynamicComponent component, MemberInfo declaringTypeMember, HbmMapping mapDoc) { this.component = component; + this.mapDoc = mapDoc; accessorPropertyMapper = new AccessorPropertyMapper(declaringTypeMember.DeclaringType, declaringTypeMember.Name, x => component.access = x); } - protected void AddProperty(object property) + private void AddProperty(object property) { - throw new NotImplementedException(); + if (property == null) + { + throw new ArgumentNullException("property"); + } + var toAdd = new[] { property }; + component.Items = component.Items == null ? toAdd : component.Items.Concat(toAdd).ToArray(); } public void Access(Accessor accessor) @@ -72,7 +80,9 @@ public void Property(MemberInfo property, Action<IPropertyMapper> mapping) { - throw new NotImplementedException(); + var hbmProperty = new HbmProperty { name = property.Name }; + mapping(new PropertyMapper(property, hbmProperty)); + AddProperty(hbmProperty); } public void Component(MemberInfo property, Action<IComponentMapper> mapping) Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs 2011-04-20 19:28:30 UTC (rev 5725) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs 2011-04-20 20:31:21 UTC (rev 5726) @@ -1,4 +1,5 @@ using System.Collections; +using System.Linq; using NHibernate.Cfg.MappingSchema; using NHibernate.Mapping.ByCode; using NHibernate.Mapping.ByCode.Impl; @@ -62,5 +63,18 @@ mapper.OptimisticLock(false); component.OptimisticLock.Should().Be.False(); } + + [Test] + public void CanAddSimpleProperty() + { + var mapdoc = new HbmMapping(); + var component = new HbmDynamicComponent(); + var mapper = new DynamicComponentMapper(component, For<Person>.Property(p => p.Info), mapdoc); + var dynObject = new { Pizza = 5 }; + mapper.Property(dynObject.GetType().GetProperty("Pizza"), x => { }); + + component.Properties.Single().Should().Be.OfType<HbmProperty>().And.ValueOf.Name.Should().Be.EqualTo("Pizza"); + } + } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-20 19:28:36
|
Revision: 5725 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5725&view=rev Author: fabiomaulo Date: 2011-04-20 19:28:30 +0000 (Wed, 20 Apr 2011) Log Message: ----------- Starting DynamicComponentMapper Modified Paths: -------------- trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/ trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs Added: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/DynamicComponentMapper.cs 2011-04-20 19:28:30 UTC (rev 5725) @@ -0,0 +1,103 @@ +using System; +using System.Reflection; +using NHibernate.Cfg.MappingSchema; + +namespace NHibernate.Mapping.ByCode.Impl +{ + public class DynamicComponentMapper : IDynamicComponentMapper + { + private readonly HbmDynamicComponent component; + private readonly IAccessorPropertyMapper accessorPropertyMapper; + + public DynamicComponentMapper(HbmDynamicComponent component, MemberInfo declaringTypeMember, HbmMapping mapDoc) + { + this.component = component; + accessorPropertyMapper = new AccessorPropertyMapper(declaringTypeMember.DeclaringType, declaringTypeMember.Name, x => component.access = x); + } + + protected void AddProperty(object property) + { + throw new NotImplementedException(); + } + + public void Access(Accessor accessor) + { + accessorPropertyMapper.Access(accessor); + } + + public void Access(System.Type accessorType) + { + accessorPropertyMapper.Access(accessorType); + } + + public void OptimisticLock(bool takeInConsiderationForOptimisticLock) + { + component.optimisticlock = takeInConsiderationForOptimisticLock; + } + + public void Update(bool consideredInUpdateQuery) + { + component.update = consideredInUpdateQuery; + } + + public void Insert(bool consideredInInsertQuery) + { + component.insert = consideredInInsertQuery; + } + + public void Set(MemberInfo property, Action<ISetPropertiesMapper> collectionMapping, Action<ICollectionElementRelation> mapping) + { + throw new NotImplementedException(); + } + + public void Bag(MemberInfo property, Action<IBagPropertiesMapper> collectionMapping, Action<ICollectionElementRelation> mapping) + { + throw new NotImplementedException(); + } + + public void List(MemberInfo property, Action<IListPropertiesMapper> collectionMapping, Action<ICollectionElementRelation> mapping) + { + throw new NotImplementedException(); + } + + public void Map(MemberInfo property, Action<IMapPropertiesMapper> collectionMapping, Action<IMapKeyRelation> keyMapping, Action<ICollectionElementRelation> mapping) + { + throw new NotImplementedException(); + } + + public void IdBag(MemberInfo property, Action<IIdBagPropertiesMapper> collectionMapping, Action<ICollectionElementRelation> mapping) + { + throw new NotImplementedException(); + } + + public void Property(MemberInfo property, Action<IPropertyMapper> mapping) + { + throw new NotImplementedException(); + } + + public void Component(MemberInfo property, Action<IComponentMapper> mapping) + { + throw new NotImplementedException(); + } + + public void Component(MemberInfo property, Action<IDynamicComponentMapper> mapping) + { + throw new NotImplementedException(); + } + + public void ManyToOne(MemberInfo property, Action<IManyToOneMapper> mapping) + { + throw new NotImplementedException(); + } + + public void Any(MemberInfo property, System.Type idTypeOfMetaType, Action<IAnyMapper> mapping) + { + throw new NotImplementedException(); + } + + public void OneToOne(MemberInfo property, Action<IOneToOneMapper> mapping) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-20 16:17:26 UTC (rev 5724) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-20 19:28:30 UTC (rev 5725) @@ -295,6 +295,7 @@ <Compile Include="Mapping\ByCode\Conformist\SubclassMapping.cs" /> <Compile Include="Mapping\ByCode\Conformist\UnionSubclassMapping.cs" /> <Compile Include="Mapping\ByCode\IDynamicComponentAttributesMapper.cs" /> + <Compile Include="Mapping\ByCode\Impl\DynamicComponentMapper.cs" /> <Compile Include="Mapping\ByCode\PropertyToField.cs" /> <Compile Include="Mapping\ByCode\SimpleModelInspector.cs" /> <Compile Include="Mapping\ByCode\ExplicitlyDeclaredModel.cs" /> Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/MappersTests/DynamicComponentMapperTests/DynCompAttributesSettingTest.cs 2011-04-20 19:28:30 UTC (rev 5725) @@ -0,0 +1,66 @@ +using System.Collections; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Impl; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.MappersTests.DynamicComponentMapperTests +{ + public class DynCompAttributesSettingTest + { + private class Person + { + public int Id { get; set; } + private IDictionary info; + public IDictionary Info + { + get { return info; } + } + } + + [Test] + public void CanSetAccessor() + { + var mapdoc = new HbmMapping(); + var component = new HbmDynamicComponent(); + var mapper = new DynamicComponentMapper(component, For<Person>.Property(p => p.Info), mapdoc); + + mapper.Access(Accessor.Field); + component.access.Should().Be("field.camelcase"); + } + + [Test] + public void CanSetUpdate() + { + var mapdoc = new HbmMapping(); + var component = new HbmDynamicComponent(); + var mapper = new DynamicComponentMapper(component, For<Person>.Property(p => p.Info), mapdoc); + + mapper.Update(false); + component.update.Should().Be.False(); + } + + [Test] + public void CanSetInsert() + { + var mapdoc = new HbmMapping(); + var component = new HbmDynamicComponent(); + var mapper = new DynamicComponentMapper(component, For<Person>.Property(p => p.Info), mapdoc); + + mapper.Insert(false); + component.insert.Should().Be.False(); + } + + [Test] + public void CanSetOptimisticLock() + { + var mapdoc = new HbmMapping(); + var component = new HbmDynamicComponent(); + var mapper = new DynamicComponentMapper(component, For<Person>.Property(p => p.Info), mapdoc); + + mapper.OptimisticLock(false); + component.OptimisticLock.Should().Be.False(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-20 16:17:26 UTC (rev 5724) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-20 19:28:30 UTC (rev 5725) @@ -550,6 +550,7 @@ <Compile Include="MappingByCode\MappersTests\ClassMapperTests\SetPersisterTests.cs" /> <Compile Include="MappingByCode\MappersTests\ClassMapperTests\TablesSincronizationTests.cs" /> <Compile Include="MappingByCode\MappersTests\CollectionIdMapperTests.cs" /> + <Compile Include="MappingByCode\MappersTests\DynamicComponentMapperTests\DynCompAttributesSettingTest.cs" /> <Compile Include="MappingByCode\MappersTests\FakeUserCollectionType.cs" /> <Compile Include="MappingByCode\MappersTests\IdBagMapperTest.cs" /> <Compile Include="MappingByCode\MappersTests\JoinedSubclassMapperTests\SetPersisterTests.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-20 16:17:32
|
Revision: 5724 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5724&view=rev Author: fabiomaulo Date: 2011-04-20 16:17:26 +0000 (Wed, 20 Apr 2011) Log Message: ----------- API to map dynamic-component (only API not implemented) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IDynamicComponentAttributesMapper.cs Added: trunk/nhibernate/src/NHibernate/Mapping/ByCode/IDynamicComponentAttributesMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IDynamicComponentAttributesMapper.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/IDynamicComponentAttributesMapper.cs 2011-04-20 16:17:26 UTC (rev 5724) @@ -0,0 +1,19 @@ +namespace NHibernate.Mapping.ByCode +{ + public interface IDynamicComponentAttributesMapper : IEntityPropertyMapper + { + void Update(bool consideredInUpdateQuery); + void Insert(bool consideredInInsertQuery); + } + + public interface IDynamicComponentMapper : IDynamicComponentAttributesMapper, IPropertyContainerMapper { } + + public interface IDynamicComponentAttributesMapper<TComponent> : IEntityPropertyMapper + { + void Update(bool consideredInUpdateQuery); + void Insert(bool consideredInInsertQuery); + } + + public interface IDynamicComponentMapper<TComponent> : IDynamicComponentAttributesMapper<TComponent>, IPropertyContainerMapper<TComponent> where TComponent : class { } + +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs 2011-04-20 12:12:23 UTC (rev 5723) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs 2011-04-20 16:17:26 UTC (rev 5724) @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Linq.Expressions; using System.Reflection; @@ -9,6 +10,7 @@ void Property(MemberInfo property, Action<IPropertyMapper> mapping); void Component(MemberInfo property, Action<IComponentMapper> mapping); + void Component(MemberInfo property, Action<IDynamicComponentMapper> mapping); void ManyToOne(MemberInfo property, Action<IManyToOneMapper> mapping); void Any(MemberInfo property, System.Type idTypeOfMetaType, Action<IAnyMapper> mapping); @@ -29,6 +31,10 @@ Action<IComponentMapper<TComponent>> mapping) where TComponent : class; void Component<TComponent>(Expression<Func<TContainer, TComponent>> property) where TComponent : class; + void Component<TComponent>(Expression<Func<TContainer, IDictionary>> property, + TComponent dynamicComponentTemplate, + Action<IDynamicComponentMapper<TComponent>> mapping) where TComponent : class; + void ManyToOne<TProperty>(Expression<Func<TContainer, TProperty>> property, Action<IManyToOneMapper> mapping) where TProperty : class; void ManyToOne<TProperty>(Expression<Func<TContainer, TProperty>> property) where TProperty : class; Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs 2011-04-20 12:12:23 UTC (rev 5723) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/AbstractBasePropertyContainerMapper.cs 2011-04-20 16:17:26 UTC (rev 5724) @@ -53,6 +53,11 @@ AddProperty(hbm); } + public virtual void Component(MemberInfo property, Action<IDynamicComponentMapper> mapping) + { + throw new NotImplementedException(); + } + public virtual void ManyToOne(MemberInfo property, Action<IManyToOneMapper> mapping) { var hbm = new HbmManyToOne {name = property.Name}; Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs 2011-04-20 12:12:23 UTC (rev 5723) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs 2011-04-20 16:17:26 UTC (rev 5724) @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; @@ -78,6 +79,13 @@ mapping(new ComponentCustomizer<TComponent>(explicitDeclarationsHolder, CustomizersHolder, new PropertyPath(PropertyPath, memberOf))); } + public void Component<TComponent>(Expression<Func<TEntity, IDictionary>> property, + TComponent dynamicComponentTemplate, + Action<IDynamicComponentMapper<TComponent>> mapping) where TComponent : class + { + throw new NotImplementedException(); + } + public void ManyToOne<TProperty>(Expression<Func<TEntity, TProperty>> property, Action<IManyToOneMapper> mapping) where TProperty : class { Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-20 12:12:23 UTC (rev 5723) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-20 16:17:26 UTC (rev 5724) @@ -294,6 +294,7 @@ <Compile Include="Mapping\ByCode\Conformist\JoinedSubclassMapping.cs" /> <Compile Include="Mapping\ByCode\Conformist\SubclassMapping.cs" /> <Compile Include="Mapping\ByCode\Conformist\UnionSubclassMapping.cs" /> + <Compile Include="Mapping\ByCode\IDynamicComponentAttributesMapper.cs" /> <Compile Include="Mapping\ByCode\PropertyToField.cs" /> <Compile Include="Mapping\ByCode\SimpleModelInspector.cs" /> <Compile Include="Mapping\ByCode\ExplicitlyDeclaredModel.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-20 12:12:29
|
Revision: 5723 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5723&view=rev Author: fabiomaulo Date: 2011-04-20 12:12:23 +0000 (Wed, 20 Apr 2011) Log Message: ----------- Apply accessor on component property Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsAccessorTests.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs 2011-04-19 18:56:09 UTC (rev 5722) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs 2011-04-20 12:12:23 UTC (rev 5723) @@ -22,6 +22,9 @@ BeforeMapProperty += MemberNoSetterToField; BeforeMapProperty += MemberReadOnlyAccessor; + BeforeMapComponent += MemberToFieldAccessor; + BeforeMapComponent += MemberNoSetterToField; + BeforeMapComponent += MemberReadOnlyAccessor; BeforeMapComponent += ComponentParentToFieldAccessor; BeforeMapComponent += ComponentParentNoSetterToField; Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsAccessorTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsAccessorTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsAccessorTests.cs 2011-04-20 12:12:23 UTC (rev 5723) @@ -0,0 +1,51 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ConventionModelMapperTests +{ + public class ComponetsAccessorTests + { + private class MyClass + { + public int Id { get; set; } + private MyCompo compo; + public MyCompo Compo + { + get { return compo; } + } + } + + private class MyCompo + { + public string Something { get; set; } + } + private HbmMapping GetMappingWithParentInCompo() + { + var mapper = new ConventionModelMapper(); + mapper.Class<MyClass>(x => + { + x.Id(c => c.Id); + x.Component(c => c.Compo); + }); + mapper.Component<MyCompo>(x => + { + x.Property(c => c.Something); + }); + return mapper.CompileMappingForAllExplicitAddedEntities(); + } + + [Test] + public void WhenMapComoponetWithNestBidirectionalComponentThenMapParentAccessor() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + + hbmMyCompo.Access.Should().Contain("camelcase"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-19 18:56:09 UTC (rev 5722) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-20 12:12:23 UTC (rev 5723) @@ -511,6 +511,7 @@ <Compile Include="Linq\ByMethod\SumTests.cs" /> <Compile Include="Logging\Log4NetLoggerTest.cs" /> <Compile Include="Logging\LoggerProviderTest.cs" /> + <Compile Include="MappingByCode\ConventionModelMapperTests\ComponetsAccessorTests.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\ComponetsParentAccessorTests.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\PropertyToFieldAccessorTest.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\SafePoidTests.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-19 18:56:15
|
Revision: 5722 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5722&view=rev Author: fabiomaulo Date: 2011-04-19 18:56:09 +0000 (Tue, 19 Apr 2011) Log Message: ----------- Apply accessor on component-parent Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsParentAccessorTests.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs 2011-04-19 18:04:58 UTC (rev 5721) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ConventionModelMapper.cs 2011-04-19 18:56:09 UTC (rev 5722) @@ -22,6 +22,9 @@ BeforeMapProperty += MemberNoSetterToField; BeforeMapProperty += MemberReadOnlyAccessor; + BeforeMapComponent += ComponentParentToFieldAccessor; + BeforeMapComponent += ComponentParentNoSetterToField; + BeforeMapBag += MemberToFieldAccessor; BeforeMapSet += MemberToFieldAccessor; BeforeMapMap += MemberToFieldAccessor; @@ -46,6 +49,32 @@ BeforeMapAny += MemberReadOnlyAccessor; } + protected virtual void ComponentParentToFieldAccessor(IModelInspector modelinspector, PropertyPath member, IComponentAttributesMapper componentMapper) + { + System.Type componentType = member.LocalMember.GetPropertyOrFieldType(); + IEnumerable<MemberInfo> persistentProperties = + MembersProvider.GetComponentMembers(componentType).Where(p => ModelInspector.IsPersistentProperty(p)); + + MemberInfo parentReferenceProperty = GetComponentParentReferenceProperty(persistentProperties, member.LocalMember.ReflectedType); + if (parentReferenceProperty != null && MatchPropertyToField(parentReferenceProperty)) + { + componentMapper.Parent(parentReferenceProperty, cp=> cp.Access(Accessor.Field)); + } + } + + protected virtual void ComponentParentNoSetterToField(IModelInspector modelinspector, PropertyPath member, IComponentAttributesMapper componentMapper) + { + System.Type componentType = member.LocalMember.GetPropertyOrFieldType(); + IEnumerable<MemberInfo> persistentProperties = + MembersProvider.GetComponentMembers(componentType).Where(p => ModelInspector.IsPersistentProperty(p)); + + MemberInfo parentReferenceProperty = GetComponentParentReferenceProperty(persistentProperties, member.LocalMember.ReflectedType); + if (parentReferenceProperty != null && MatchNoSetterProperty(parentReferenceProperty)) + { + componentMapper.Parent(parentReferenceProperty, cp => cp.Access(Accessor.NoSetter)); + } + } + protected virtual void MemberReadOnlyAccessor(IModelInspector modelInspector, PropertyPath member, IAccessorPropertyMapper propertyCustomizer) { if (MatchReadOnlyProperty(member.LocalMember)) Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 18:04:58 UTC (rev 5721) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 18:56:09 UTC (rev 5722) @@ -1038,11 +1038,7 @@ MemberInfo parentReferenceProperty = GetComponentParentReferenceProperty(persistentProperties, propertiesContainerType); if (parentReferenceProperty != null) { - componentMapper.Parent(parentReferenceProperty, - componentParentMapper => - { - /* TODO */ - }); + componentMapper.Parent(parentReferenceProperty); } customizerHolder.InvokeCustomizers(componentType, componentMapper); ForEachMemberPath(member, memberPath, pp => customizerHolder.InvokeCustomizers(pp, componentMapper)); @@ -1243,12 +1239,7 @@ MemberInfo parentReferenceProperty = modelMapper.GetComponentParentReferenceProperty(persistentProperties, ownerType); if (parentReferenceProperty != null) { - x.Parent(parentReferenceProperty, - componentParentMapper => - { - /* TODO */ - } - ); + x.Parent(parentReferenceProperty); } customizersHolder.InvokeCustomizers(componentType, x); @@ -1300,10 +1291,7 @@ MemberInfo parentReferenceProperty = modelMapper.GetComponentParentReferenceProperty(componentProperties, componentOwnerType); if (parentReferenceProperty != null) { - x.Parent(parentReferenceProperty, componentParentMapper => - { - /* TODO */ - }); + x.Parent(parentReferenceProperty); } customizersHolder.InvokeCustomizers(componentPropertyType, x); modelMapper.ForEachMemberPath(member, propertyPath, pp => customizersHolder.InvokeCustomizers(pp, x)); Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsParentAccessorTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsParentAccessorTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ConventionModelMapperTests/ComponetsParentAccessorTests.cs 2011-04-19 18:56:09 UTC (rev 5722) @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ConventionModelMapperTests +{ + public class ComponetsParentAccessorTests + { + private class MyClass + { + public int Id { get; set; } + public MyCompo Compo { get; set; } + public IEnumerable<MyCompo> Compos { get; set; } + } + + private class MyCompo + { + private MyClass parent; + public MyClass Parent + { + get { return parent; } + } + + public MyNestedCompo NestedCompo { get; set; } + } + + private class MyNestedCompo + { + private MyCompo owner; + public MyCompo Owner + { + get { return owner; } + } + + public string Something { get; set; } + } + + private HbmMapping GetMappingWithParentInCompo() + { + var mapper = new ConventionModelMapper(); + mapper.Class<MyClass>(x => + { + x.Id(c => c.Id); + x.Component(c => c.Compo); + x.Bag(c => c.Compos, cm => { }); + }); + mapper.Component<MyCompo>(x => + { + x.Parent(c => c.Parent); + x.Component(c => c.NestedCompo); + }); + mapper.Component<MyNestedCompo>(x => + { + x.Component(c => c.Owner); + x.Property(c => c.Something); + }); + return mapper.CompileMappingForAllExplicitAddedEntities(); + } + + [Test] + public void WhenMapComoponetWithNestBidirectionalComponentThenMapParentAccessor() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + var hbmMyNestedCompo = hbmMyCompo.Properties.OfType<HbmComponent>().Single(); + + hbmMyNestedCompo.Parent.access.Should().Contain("camelcase"); + } + + [Test] + public void WhenCollectionOfComoponetsWithNestBidirectionalComponentThenMapParentAccessor() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmBag = hbmClass.Properties.OfType<HbmBag>().Single(); + + var hbmMyCompo = (HbmCompositeElement)hbmBag.ElementRelationship; + var hbmMyNestedCompo = hbmMyCompo.Properties.OfType<HbmNestedCompositeElement>().Single(); + + hbmMyNestedCompo.Parent.access.Should().Contain("camelcase"); + } + + [Test, Ignore("No fixed yet. When the parent is an entity it should be managed explicitly as explicitly is managed the relation (Parent instead many-to-one)")] + public void WhenMapComoponetWithParentThenMapParentAccessor() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + hbmMyCompo.Parent.access.Should().Contain("camelcase"); + } + + [Test, Ignore("No fixed yet. When the parent is an entity it should be managed explicitly as explicitly is managed the relation (Parent instead many-to-one)")] + public void WhenCollectionOfComoponetsWithParentThenMapParentAccessor() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmBag = hbmClass.Properties.OfType<HbmBag>().Single(); + + var hbmMyCompo = (HbmCompositeElement)hbmBag.ElementRelationship; + hbmMyCompo.Parent.access.Should().Contain("camelcase"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-19 18:04:58 UTC (rev 5721) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-19 18:56:09 UTC (rev 5722) @@ -511,6 +511,7 @@ <Compile Include="Linq\ByMethod\SumTests.cs" /> <Compile Include="Logging\Log4NetLoggerTest.cs" /> <Compile Include="Logging\LoggerProviderTest.cs" /> + <Compile Include="MappingByCode\ConventionModelMapperTests\ComponetsParentAccessorTests.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\PropertyToFieldAccessorTest.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\SafePoidTests.cs" /> <Compile Include="MappingByCode\ConventionModelMapperTests\VersionOnBaseClassIntegrationTest.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-19 18:05:05
|
Revision: 5721 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5721&view=rev Author: fabiomaulo Date: 2011-04-19 18:04:58 +0000 (Tue, 19 Apr 2011) Log Message: ----------- Refactoring Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 17:50:26 UTC (rev 5720) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 18:04:58 UTC (rev 5721) @@ -1035,9 +1035,7 @@ IEnumerable<MemberInfo> persistentProperties = membersProvider.GetComponentMembers(componentType).Where(p => modelInspector.IsPersistentProperty(p)); - MemberInfo parentReferenceProperty = modelInspector.IsComponent(propertiesContainerType) - ? persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == propertiesContainerType) - : null; + MemberInfo parentReferenceProperty = GetComponentParentReferenceProperty(persistentProperties, propertiesContainerType); if (parentReferenceProperty != null) { componentMapper.Parent(parentReferenceProperty, @@ -1054,6 +1052,13 @@ }); } + protected MemberInfo GetComponentParentReferenceProperty(IEnumerable<MemberInfo> persistentProperties, System.Type propertiesContainerType) + { + return modelInspector.IsComponent(propertiesContainerType) + ? persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == propertiesContainerType) + : null; + } + private void MapBag(MemberInfo member, PropertyPath propertyPath, System.Type propertyType, ICollectionPropertiesContainerMapper propertiesContainer, System.Type propertiesContainerType) { @@ -1232,26 +1237,24 @@ public void Map(ICollectionElementRelation relation) { relation.Component(x => - { - IEnumerable<MemberInfo> persistentProperties = GetPersistentProperties(componentType); + { + IEnumerable<MemberInfo> persistentProperties = GetPersistentProperties(componentType); - MemberInfo parentReferenceProperty = domainInspector.IsComponent(ownerType) - ? persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == ownerType) - : null; - if (parentReferenceProperty != null) - { - x.Parent(parentReferenceProperty, - componentParentMapper => - { + MemberInfo parentReferenceProperty = modelMapper.GetComponentParentReferenceProperty(persistentProperties, ownerType); + if (parentReferenceProperty != null) + { + x.Parent(parentReferenceProperty, + componentParentMapper => + { /* TODO */ - } - ); - } - customizersHolder.InvokeCustomizers(componentType, x); + } + ); + } + customizersHolder.InvokeCustomizers(componentType, x); - var propertyPath = new PropertyPath(null, collectionMember); - MapProperties(componentType, propertyPath, x, persistentProperties.Where(pi => pi != parentReferenceProperty)); - }); + var propertyPath = new PropertyPath(null, collectionMember); + MapProperties(componentType, propertyPath, x, persistentProperties.Where(pi => pi != parentReferenceProperty)); + }); } public void MapCollectionProperties(ICollectionPropertiesMapper mapped) {} @@ -1294,7 +1297,7 @@ IEnumerable<MemberInfo> componentProperties = GetPersistentProperties(componentPropertyType); - MemberInfo parentReferenceProperty = componentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == componentOwnerType); + MemberInfo parentReferenceProperty = modelMapper.GetComponentParentReferenceProperty(componentProperties, componentOwnerType); if (parentReferenceProperty != null) { x.Parent(parentReferenceProperty, componentParentMapper => This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-19 17:50:32
|
Revision: 5720 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5720&view=rev Author: fabiomaulo Date: 2011-04-19 17:50:26 +0000 (Tue, 19 Apr 2011) Log Message: ----------- Fixed nested components with parent Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/BagOfNestedComponentsWithParentTest.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/NestedComponetsTests.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 17:36:06 UTC (rev 5719) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-19 17:50:26 UTC (rev 5720) @@ -1030,14 +1030,23 @@ { propertiesContainer.Component(member, componentMapper => { - InvokeBeforeMapComponent(memberPath, componentMapper); + InvokeBeforeMapComponent(memberPath, componentMapper); // <<== perhaps is better after find the parent System.Type componentType = propertyType; IEnumerable<MemberInfo> persistentProperties = membersProvider.GetComponentMembers(componentType).Where(p => modelInspector.IsPersistentProperty(p)); - MemberInfo parentReferenceProperty = persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == propertiesContainerType); - - customizerHolder.InvokeCustomizers(componentType, componentMapper); + MemberInfo parentReferenceProperty = modelInspector.IsComponent(propertiesContainerType) + ? persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == propertiesContainerType) + : null; + if (parentReferenceProperty != null) + { + componentMapper.Parent(parentReferenceProperty, + componentParentMapper => + { + /* TODO */ + }); + } + customizerHolder.InvokeCustomizers(componentType, componentMapper); ForEachMemberPath(member, memberPath, pp => customizerHolder.InvokeCustomizers(pp, componentMapper)); InvokeAfterMapComponent(memberPath, componentMapper); @@ -1225,7 +1234,10 @@ relation.Component(x => { IEnumerable<MemberInfo> persistentProperties = GetPersistentProperties(componentType); - MemberInfo parentReferenceProperty = persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == ownerType); + + MemberInfo parentReferenceProperty = domainInspector.IsComponent(ownerType) + ? persistentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == ownerType) + : null; if (parentReferenceProperty != null) { x.Parent(parentReferenceProperty, @@ -1281,6 +1293,7 @@ System.Type componentPropertyType = propertyType; IEnumerable<MemberInfo> componentProperties = GetPersistentProperties(componentPropertyType); + MemberInfo parentReferenceProperty = componentProperties.FirstOrDefault(pp => pp.GetPropertyOrFieldType() == componentOwnerType); if (parentReferenceProperty != null) { Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/BagOfNestedComponentsWithParentTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/BagOfNestedComponentsWithParentTest.cs 2011-04-19 17:36:06 UTC (rev 5719) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/BagOfNestedComponentsWithParentTest.cs 2011-04-19 17:50:26 UTC (rev 5720) @@ -105,10 +105,14 @@ collection.ElementRelationship.Should().Be.OfType<HbmCompositeElement>(); var elementRelation = (HbmCompositeElement)collection.ElementRelationship; elementRelation.Class.Should().Contain("Address"); - elementRelation.Properties.Should().Have.Count.EqualTo(2); - elementRelation.Properties.Select(p => p.Name).Should().Have.SameValuesAs("Street", "Number"); - elementRelation.Parent.Should().Not.Be.Null(); - elementRelation.Parent.name.Should().Be.EqualTo("Owner"); + + // This test was modified because when the "owner" is an entity it can be mapped as many-to-one or as parent and without an explicit + // definition of the property representing the bidiretional-relation we can't know is the mapping element (many-to-one or parent) + elementRelation.Properties.Should().Have.Count.EqualTo(3); + elementRelation.Properties.Select(p => p.Name).Should().Have.SameValuesAs("Street", "Number", "Owner"); + //elementRelation.Parent.Should().Not.Be.Null(); + //elementRelation.Parent.name.Should().Be.EqualTo("Owner"); + // Nested var propertyNestedRelation = elementRelation.Properties.FirstOrDefault(p => p.Name == "Number"); propertyNestedRelation.Should().Not.Be.Null().And.Be.OfType<HbmNestedCompositeElement>(); Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/NestedComponetsTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/NestedComponetsTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/NestedComponetsTests.cs 2011-04-19 17:50:26 UTC (rev 5720) @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ExpliticMappingTests +{ + public class NestedComponetsTests + { + private class MyClass + { + public int Id { get; set; } + public MyCompo Compo { get; set; } + public IEnumerable<MyCompo> Compos { get; set; } + } + + private class MyCompo + { + public MyClass AManyToOne { get; set; } + public MyNestedCompo NestedCompo { get; set; } + } + + private class MyNestedCompo + { + public MyCompo Owner { get; set; } + public string Something { get; set; } + } + + private HbmMapping GetMappingWithManyToOneInCompo() + { + var mapper = new ModelMapper(); + mapper.Class<MyClass>(x => + { + x.Id(c => c.Id); + x.Component(c => c.Compo); + x.Bag(c => c.Compos, cm => { }); + }); + mapper.Component<MyCompo>(x => + { + x.ManyToOne(c => c.AManyToOne); + x.Component(c => c.NestedCompo); + }); + mapper.Component<MyNestedCompo>(x => + { + x.Component(c => c.Owner); + x.Property(c => c.Something); + }); + return mapper.CompileMappingForAllExplicitAddedEntities(); + } + + private HbmMapping GetMappingWithParentInCompo() + { + var mapper = new ModelMapper(); + mapper.Class<MyClass>(x => + { + x.Id(c => c.Id); + x.Component(c => c.Compo); + x.Bag(c => c.Compos, cm => { }); + }); + mapper.Component<MyCompo>(x => + { + x.Parent(c => c.AManyToOne); + x.Component(c => c.NestedCompo); + }); + mapper.Component<MyNestedCompo>(x => + { + x.Component(c => c.Owner); + x.Property(c => c.Something); + }); + return mapper.CompileMappingForAllExplicitAddedEntities(); + } + + [Test] + public void WhenMapComoponetWithNestBidirectionalComponentThenMapParent() + { + HbmMapping mapping = GetMappingWithManyToOneInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + var hbmMyNestedCompo = hbmMyCompo.Properties.OfType<HbmComponent>().Single(); + + hbmMyNestedCompo.Properties.Should().Have.Count.EqualTo(1); + hbmMyNestedCompo.Parent.Should().Not.Be.Null(); + hbmMyNestedCompo.Parent.name.Should().Be("Owner"); + } + + [Test] + public void WhenCollectionOfComoponetsWithNestBidirectionalComponentThenMapParent() + { + HbmMapping mapping = GetMappingWithManyToOneInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmBag = hbmClass.Properties.OfType<HbmBag>().Single(); + + var hbmMyCompo = (HbmCompositeElement)hbmBag.ElementRelationship; + var hbmMyNestedCompo = hbmMyCompo.Properties.OfType<HbmNestedCompositeElement>().Single(); + + hbmMyNestedCompo.Properties.Should().Have.Count.EqualTo(1); + hbmMyNestedCompo.Parent.Should().Not.Be.Null(); + hbmMyNestedCompo.Parent.name.Should().Be("Owner"); + } + + [Test] + public void WhenMapComoponetWithManyToOneThenMapManyToOne() + { + HbmMapping mapping = GetMappingWithManyToOneInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + hbmMyCompo.Properties.OfType<HbmManyToOne>().Should().Have.Count.EqualTo(1); + hbmMyCompo.Parent.Should().Be.Null(); + } + + [Test] + public void WhenCollectionOfComoponetsWithManyToOneThenMapManyToOne() + { + HbmMapping mapping = GetMappingWithManyToOneInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmBag = hbmClass.Properties.OfType<HbmBag>().Single(); + + var hbmMyCompo = (HbmCompositeElement)hbmBag.ElementRelationship; + hbmMyCompo.Properties.OfType<HbmManyToOne>().Should().Have.Count.EqualTo(1); + hbmMyCompo.Parent.Should().Be.Null(); + } + + [Test] + public void WhenMapComoponetWithParentThenMapParent() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmMyCompo = hbmClass.Properties.OfType<HbmComponent>().Single(); + hbmMyCompo.Properties.OfType<HbmManyToOne>().Should().Be.Empty(); + hbmMyCompo.Parent.Should().Not.Be.Null(); + hbmMyCompo.Parent.name.Should().Be("AManyToOne"); + } + + [Test] + public void WhenCollectionOfComoponetsWithParentThenMapParent() + { + HbmMapping mapping = GetMappingWithParentInCompo(); + + var hbmClass = mapping.RootClasses[0]; + var hbmBag = hbmClass.Properties.OfType<HbmBag>().Single(); + + var hbmMyCompo = (HbmCompositeElement)hbmBag.ElementRelationship; + hbmMyCompo.Properties.OfType<HbmManyToOne>().Should().Be.Empty(); + hbmMyCompo.Parent.Should().Not.Be.Null(); + hbmMyCompo.Parent.name.Should().Be("AManyToOne"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-19 17:36:06 UTC (rev 5719) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-19 17:50:26 UTC (rev 5720) @@ -537,6 +537,7 @@ <Compile Include="MappingByCode\ExpliticMappingTests\IdBagMappingTest.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\MappingOfPrivateMembersOnRootEntity.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\NaturalIdTests.cs" /> + <Compile Include="MappingByCode\ExpliticMappingTests\NestedComponetsTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\PoidTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\RootClassPropertiesSplitsTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\SubclassPropertiesSplitsTests.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-19 17:36:14
|
Revision: 5719 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5719&view=rev Author: patearl Date: 2011-04-19 17:36:06 +0000 (Tue, 19 Apr 2011) Log Message: ----------- Linq: Fixed typo in assertion error message. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-18 21:24:23 UTC (rev 5718) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-19 17:36:06 UTC (rev 5719) @@ -289,7 +289,7 @@ if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0) { if (expression.Type != typeof(bool)) - throw new AssertionFailure("Was expected a boolean member expression."); + throw new AssertionFailure("Was expecting a boolean member expression."); addOwnMemberExpressionMapping = true; _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); } @@ -319,7 +319,7 @@ if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0) { if (expression.Type != typeof(bool)) - throw new AssertionFailure("Was expected a boolean member expression."); + throw new AssertionFailure("Was expecting a boolean member expression."); addOwnMemberExpressionMapping = true; _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-18 21:24:31
|
Revision: 5718 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5718&view=rev Author: fabiomaulo Date: 2011-04-18 21:24:23 +0000 (Mon, 18 Apr 2011) Log Message: ----------- - Sync between proxy-validator and proxy-factory - removed no more used exception about proxy-factory-factory Breaking Change: what was "only" a log-error in PocoEntityTuplizer.LogPropertyAccessorsErrors is now checked by the proxy-validator and an early exception is thrown when the proxy-validator is active. Modified Paths: -------------- trunk/nhibernate/releasenotes.txt trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs trunk/nhibernate/src/NHibernate/Linq/Functions/DictionaryGenerator.cs trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate/Proxy/DynProxyTypeValidator.cs trunk/nhibernate/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs trunk/nhibernate/src/NHibernate/Util/ReflectHelper.cs trunk/nhibernate/src/NHibernate.Test/Insertordering/Membership.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1343/OrderLine.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1584/Cat.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Area.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/City.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Country.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Person.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1864/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1868/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1904/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1908/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1922/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1925/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1927/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1928/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2245/Model.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2420/MyTable.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2632/Domain.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj trunk/nhibernate/src/NHibernate.Test/UtilityTest/ReflectionHelperIsMethodOfTests.cs trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/ComplexDomain.cs trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/SimpleVersioned.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Bytecode/ProxyFactoryFactoryNotConfiguredException.cs Modified: trunk/nhibernate/releasenotes.txt =================================================================== --- trunk/nhibernate/releasenotes.txt 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/releasenotes.txt 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,9 +4,11 @@ ##### Possible Breaking Changes ##### * [NH-2550] - Allow public access to FieldInterceptor Session (IFieldInterceptor changed) - * [NH-2593] - Form Microsoft SQL Server the default batch-size (adonet.batch_size) is set to 20 where not explicit defined in the session-factory configuration + * [NH-2593] - For Microsoft SQL Server the default batch-size (adonet.batch_size) is set to 20 where not explicit defined in the session-factory configuration * - ICollectionPersister added property to fix [NH-2489] * [NH-2605] Refactorize MultiQuery/MultiCriteria implementation to delegate responsibility to IDrive (IDrive changed). + * For users who don't look at Log-ERROR, to prevent wrong behavior when lazy-properties are used the DynamicProxyValidator validates the accessability of properties setters. + Build 3.2.0.Aplha2 (rev5715) ============================= ** Bug Deleted: trunk/nhibernate/src/NHibernate/Bytecode/ProxyFactoryFactoryNotConfiguredException.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Bytecode/ProxyFactoryFactoryNotConfiguredException.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Bytecode/ProxyFactoryFactoryNotConfiguredException.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -1,29 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace NHibernate.Bytecode -{ - - [Serializable] - public class ProxyFactoryFactoryNotConfiguredException : HibernateByteCodeException - { - public ProxyFactoryFactoryNotConfiguredException() {} - - protected ProxyFactoryFactoryNotConfiguredException(SerializationInfo info, - StreamingContext context) : base(info, context) {} - - public override string Message - { - get - { - const string msg = @"The ProxyFactoryFactory was not configured. -Initialize 'proxyfactory.factory_class' property of the session-factory configuration section with one of the available NHibernate.ByteCode providers. -Example: -<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property> -Example: -<property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>"; - return msg; - } - } - } -} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Linq/EnumerableHelper.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -55,58 +55,6 @@ } return ((MemberExpression)property.Body).Member; } - - /// <summary> - /// Check if a method is declared in a given <see cref="System.Type"/>. - /// </summary> - /// <param name="source">The method to check.</param> - /// <param name="realDeclaringType">The where the method is really declared.</param> - /// <returns>True if the method is an implementation of the method declared in <paramref name="realDeclaringType"/>; false otherwise. </returns> - public static bool IsMethodOf(this MethodInfo source, System.Type realDeclaringType) - { - if (source == null) - { - throw new ArgumentNullException("source"); - } - if (realDeclaringType == null) - { - throw new ArgumentNullException("realDeclaringType"); - } - var methodDeclaringType = source.DeclaringType; - if(realDeclaringType.Equals(methodDeclaringType)) - { - return true; - } - if (methodDeclaringType.IsGenericType && !methodDeclaringType.IsGenericTypeDefinition && - realDeclaringType.Equals(methodDeclaringType.GetGenericTypeDefinition())) - { - return true; - } - if (realDeclaringType.IsInterface) - { - var declaringTypeInterfaces = methodDeclaringType.GetInterfaces(); - if(declaringTypeInterfaces.Contains(realDeclaringType)) - { - var methodsMap = methodDeclaringType.GetInterfaceMap(realDeclaringType); - if(methodsMap.TargetMethods.Contains(source)) - { - return true; - } - } - if (realDeclaringType.IsGenericTypeDefinition) - { - bool implements = declaringTypeInterfaces - .Where(t => t.IsGenericType && t.GetGenericTypeDefinition().Equals(realDeclaringType)) - .Select(implementedGenericInterface => methodDeclaringType.GetInterfaceMap(implementedGenericInterface)) - .Any(methodsMap => methodsMap.TargetMethods.Contains(source)); - if (implements) - { - return true; - } - } - } - return false; - } } // TODO rename / remove - reflection helper above is better Modified: trunk/nhibernate/src/NHibernate/Linq/Functions/DictionaryGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/DictionaryGenerator.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/DictionaryGenerator.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -6,6 +6,7 @@ using System.Reflection; using NHibernate.Hql.Ast; using NHibernate.Linq.Visitors; +using NHibernate.Util; namespace NHibernate.Linq.Functions { Modified: trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Linq/Functions/QueryableGenerator.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -5,6 +5,7 @@ using System.Reflection; using NHibernate.Hql.Ast; using NHibernate.Linq.Visitors; +using NHibernate.Util; namespace NHibernate.Linq.Functions { Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-18 21:24:23 UTC (rev 5718) @@ -496,6 +496,7 @@ <Compile Include="Properties\PascalCaseMUnderscoreStrategy.cs" /> <Compile Include="Properties\PascalCaseUnderscoreStrategy.cs" /> <Compile Include="Properties\PropertyAccessorFactory.cs" /> + <Compile Include="Proxy\DefaultDynamicProxyMethodCheckerExtensions.cs" /> <Compile Include="Proxy\DefaultLazyInitializer.cs" /> <Compile Include="Proxy\DefaultProxyFactory.cs" /> <Compile Include="Proxy\DynamicProxy\DefaultArgumentHandler.cs" /> @@ -680,7 +681,6 @@ <Compile Include="Bytecode\HibernateByteCodeException.cs" /> <Compile Include="Bytecode\IInjectableCollectionTypeFactoryClass.cs" /> <Compile Include="Bytecode\IObjectsFactory.cs" /> - <Compile Include="Bytecode\ProxyFactoryFactoryNotConfiguredException.cs" /> <Compile Include="Bytecode\UnableToLoadProxyFactoryFactoryException.cs" /> <Compile Include="Cache\FakeCache.cs" /> <Compile Include="Cfg\BindMappingEventArgs.cs" /> Added: trunk/nhibernate/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using System.Reflection; +using NHibernate.Util; + +namespace NHibernate.Proxy +{ + public static class DefaultDynamicProxyMethodCheckerExtensions + { + public static bool IsProxiable(this MethodInfo method) + { + return !method.IsFinal + && (method.DeclaringType != typeof(MarshalByRefObject)) + && (method.DeclaringType != typeof(object) || !"finalize".Equals(method.Name.ToLowerInvariant())) + && + ( + ((method.IsPublic || method.IsFamily) && (method.IsVirtual || method.IsAbstract)) // public or protected (virtual) + || + (method.IsFamilyOrAssembly && (method.IsVirtual || method.IsAbstract)) // internal protected virtual + ); + } + + public static bool ShouldBeProxiable(this MethodInfo method) + { + // to use only for real methods (no getter/setter) + return (method.DeclaringType != typeof (MarshalByRefObject)) && + (method.DeclaringType != typeof (object) || !"finalize".Equals(method.Name.ToLowerInvariant())) && + (!(method.DeclaringType == typeof (object) && "GetType".Equals(method.Name))) && + !IsDisposeMethod(method) && + (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly); + } + + public static bool ShouldBeProxiable(this PropertyInfo propertyInfo) + { + if(propertyInfo != null) + { + var accessors = propertyInfo.GetAccessors(true); + return accessors.Where(x => x.IsPublic || x.IsAssembly || x.IsFamilyOrAssembly).Any(); + } + return true; + } + + private static bool IsDisposeMethod(MethodInfo method) + { + // NH-1464 + return method.Name.Equals("Dispose") && method.MemberType == MemberTypes.Method && method.GetParameters().Length == 0; + // return method.Name.Equals("Dispose") && method.IsMethodOf(typeof(IDisposable)); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Proxy/DynProxyTypeValidator.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Proxy/DynProxyTypeValidator.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Proxy/DynProxyTypeValidator.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -52,36 +52,44 @@ if (member is PropertyInfo) { var property = (PropertyInfo) member; - MethodInfo[] accessors = property.GetAccessors(false); + if(property.ShouldBeProxiable()) + { + MethodInfo[] accessors = property.GetAccessors(true); - if (accessors != null) - { - foreach (var accessor in accessors) + if (accessors != null) { - CheckMethodIsVirtual(type, accessor); + foreach (var accessor in accessors) + { + CheckMethodIsVirtual(type, accessor); + } } } } else if (member is MethodInfo) { - if (member.DeclaringType == typeof (object) && member.Name == "GetType") + var methodInfo = (MethodInfo) member; + // avoid the check of properties getter and setter because already checked when the PropertyInfo was found. + if (!IsPropertyMethod(methodInfo) && methodInfo.ShouldBeProxiable()) { - // object.GetType is ignored - continue; + CheckMethodIsVirtual(type, methodInfo); } - CheckMethodIsVirtual(type, (MethodInfo) member); } else if (member is FieldInfo) { var memberField = (FieldInfo) member; if (memberField.IsPublic || memberField.IsAssembly || memberField.IsFamilyOrAssembly) { - EnlistError(type, "field " + member.Name + " should not be public nor internal"); + EnlistError(type, "field " + member.Name + " should not be public nor internal (ecapsulate it in a property)."); } } } } + private bool IsPropertyMethod(MethodInfo methodInfo) + { + return methodInfo.IsSpecialName && (methodInfo.Name.StartsWith("get_") || methodInfo.Name.StartsWith("set_")); + } + protected virtual void CheckMethodIsVirtual(System.Type type, MethodInfo method) { if (!IsProxeable(method)) @@ -92,17 +100,11 @@ public virtual bool IsProxeable(MethodInfo method) { - // In NET if IsVirtual is false or IsFinal is true, then the method cannot be overridden. - return !(method.DeclaringType != typeof (object) && !IsDisposeMethod(method) - && (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly) - && (!method.IsVirtual || method.IsFinal || (method.IsVirtual && method.IsAssembly))); + // NH: this method is used even when the proxy-validation at start-up is turned off to check each persistent property (only persistent properties). + // it must be in sync with what is really proxiable by the proxy-factory. + return method.IsProxiable(); } - protected static bool IsDisposeMethod(MethodBase method) - { - return method.Name.Equals("Dispose") && method.MemberType == MemberTypes.Method && method.GetParameters().Length == 0; - } - protected virtual bool HasVisibleDefaultConstructor(System.Type type) { ConstructorInfo constructor = Modified: trunk/nhibernate/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Proxy/DynamicProxy/ProxyFactory.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -173,20 +173,10 @@ const BindingFlags candidateMethodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; return type.GetMethods(candidateMethodsBindingFlags) - .Where(method => IsProxiable(method)) + .Where(method=> method.IsProxiable()) .Concat(interfaces.SelectMany(interfaceType => interfaceType.GetMethods())).Distinct(); } - private bool IsProxiable(MethodInfo method) - { - return ( - ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly) && (method.IsVirtual || method.IsAbstract)) - && !method.IsFinal - && (method.DeclaringType != typeof (MarshalByRefObject))) - && (method.DeclaringType != typeof (object) || !"finalize".Equals(method.Name.ToLowerInvariant()) - ); - } - private static ConstructorBuilder DefineConstructor(TypeBuilder typeBuilder) { const MethodAttributes constructorAttributes = MethodAttributes.Public | Modified: trunk/nhibernate/src/NHibernate/Util/ReflectHelper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Util/ReflectHelper.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate/Util/ReflectHelper.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -689,5 +689,57 @@ } return HasProperty(source.BaseType, propertyName) || source.GetInterfaces().Any(@interface => HasProperty(@interface, propertyName)); } - } + + /// <summary> + /// Check if a method is declared in a given <see cref="System.Type"/>. + /// </summary> + /// <param name="source">The method to check.</param> + /// <param name="realDeclaringType">The where the method is really declared.</param> + /// <returns>True if the method is an implementation of the method declared in <paramref name="realDeclaringType"/>; false otherwise. </returns> + public static bool IsMethodOf(this MethodInfo source, System.Type realDeclaringType) + { + if (source == null) + { + throw new ArgumentNullException("source"); + } + if (realDeclaringType == null) + { + throw new ArgumentNullException("realDeclaringType"); + } + var methodDeclaringType = source.DeclaringType; + if(realDeclaringType.Equals(methodDeclaringType)) + { + return true; + } + if (methodDeclaringType.IsGenericType && !methodDeclaringType.IsGenericTypeDefinition && + realDeclaringType.Equals(methodDeclaringType.GetGenericTypeDefinition())) + { + return true; + } + if (realDeclaringType.IsInterface) + { + var declaringTypeInterfaces = methodDeclaringType.GetInterfaces(); + if(declaringTypeInterfaces.Contains(realDeclaringType)) + { + var methodsMap = methodDeclaringType.GetInterfaceMap(realDeclaringType); + if(methodsMap.TargetMethods.Contains(source)) + { + return true; + } + } + if (realDeclaringType.IsGenericTypeDefinition) + { + bool implements = declaringTypeInterfaces + .Where(t => t.IsGenericType && t.GetGenericTypeDefinition().Equals(realDeclaringType)) + .Select(implementedGenericInterface => methodDeclaringType.GetInterfaceMap(implementedGenericInterface)) + .Any(methodsMap => methodsMap.TargetMethods.Contains(source)); + if (implements) + { + return true; + } + } + } + return false; + } + } } Modified: trunk/nhibernate/src/NHibernate.Test/Insertordering/Membership.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/Insertordering/Membership.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/Insertordering/Membership.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -16,8 +16,8 @@ } public virtual int Id { get; protected set; } - public virtual User User { get; private set; } - public virtual Group Group { get; private set; } - public virtual DateTime ActivationDate { get; private set; } + public virtual User User { get; protected set; } + public virtual Group Group { get; protected set; } + public virtual DateTime ActivationDate { get; protected set; } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1343/OrderLine.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1343/OrderLine.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1343/OrderLine.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -10,7 +10,7 @@ Product = product; } - public virtual int Id { get; private set; } + public virtual int Id { get; protected set; } public virtual string Description { get; set; } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1584/Cat.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1584/Cat.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1584/Cat.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,7 +2,7 @@ { public abstract class Cat { - public virtual int Id { get; private set; } + public virtual int Id { get; protected set; } public virtual string Name { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Area.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Area.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Area.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,10 +4,10 @@ { public abstract class Area { - public virtual string Code { get; private set; } - public virtual string Name { get; private set; } - public virtual int Version { get; private set; } - public virtual IDictionary<int, AreaStatistics> Statistics { get; private set; } + public virtual string Code { get; protected set; } + public virtual string Name { get; protected set; } + public virtual int Version { get; protected set; } + public virtual IDictionary<int, AreaStatistics> Statistics { get; protected set; } protected Area() {} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/City.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/City.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/City.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,7 +2,7 @@ { public class City : Area { - public virtual Country Country { get; private set; } + public virtual Country Country { get; protected set; } protected City() {} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Country.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Country.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Country.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,8 +4,8 @@ { public class Country : Area { - public virtual IList<string> Routes { get; private set; } - public virtual IList<City> Cities { get; private set; } + public virtual IList<string> Routes { get; protected set; } + public virtual IList<City> Cities { get; protected set; } protected Country() {} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Person.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Person.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1612/Person.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,9 +4,9 @@ { public class Person { - public virtual Guid PersonId { get; private set; } - public virtual string Name { get; private set; } - public virtual int Version { get; private set; } + public virtual Guid PersonId { get; protected set; } + public virtual string Name { get; protected set; } + public virtual int Version { get; protected set; } protected Person() {} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1693/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,7 +2,7 @@ { public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual string Mode { get; set; } public virtual int Category { get; set; } public virtual int Num { get; set; } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1864/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1864/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1864/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,13 +4,13 @@ { public class Category { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } } public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } public virtual int Foo { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1868/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1868/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1868/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,19 +4,19 @@ { public class Category { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } } public class Package { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } } public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } public virtual Category Category { get; set; } public virtual Package Package { get; set; } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1904/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1904/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1904/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,7 +4,7 @@ { public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime Issued { get; set; } protected virtual DateTime issued { get; set; } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1908/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1908/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1908/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,14 +4,14 @@ { public class Category { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual Category ParentCategory { get; set; } public virtual DateTime ValidUntil { get; set; } } public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime Issued { get; set; } public virtual Category Category { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1922/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1922/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1922/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -5,7 +5,7 @@ { public class Customer { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1925/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1925/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1925/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,14 +4,14 @@ { public class Customer { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual ISet<Invoice> Invoices { get; set; } public virtual string Name { get; set; } } public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual Customer Customer { get; set; } public virtual int Number { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1927/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1927/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1927/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -5,14 +5,14 @@ { public class Customer { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual ISet<Invoice> Invoices { get; set; } public virtual DateTime ValidUntil { get; set; } } public class Invoice { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual DateTime ValidUntil { get; set; } public virtual Customer Customer { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1928/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1928/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH1928/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,7 +2,7 @@ { public class Customer { - public virtual int ID { get; private set; } + public virtual int ID { get; protected set; } public virtual string Name { get; set; } public virtual int Age { get; set; } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2245/Model.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2245/Model.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2245/Model.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -6,7 +6,7 @@ public class Foo { public Foo() {} - public virtual Guid Id {get; private set;} + public virtual Guid Id { get; protected set; } public virtual string Name {get; set;} public virtual string Description {get; set;} public virtual int Version{get; set;} Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2420/MyTable.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2420/MyTable.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2420/MyTable.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -4,7 +4,7 @@ { public class MyTable { - public virtual int Id { get; private set; } + public virtual int Id { get; protected set; } public virtual string String { get; set; } } } \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2632/Domain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2632/Domain.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2632/Domain.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -8,7 +8,7 @@ public virtual Int64 Id { get; - private set; + protected set; } public virtual String Name { @@ -23,7 +23,7 @@ public virtual IEnumerable<Order> Orders { get; - private set; + protected set; } } @@ -32,7 +32,7 @@ public virtual Int32 Id { get; - private set; + protected set; } public virtual DateTime Date Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -240,6 +240,21 @@ public void VirtualPublicImplementsInterface() { Assert.Throws<InvalidProxyTypeException>(() => Validate(typeof(NonVirtualPublicImplementsInterface))); - } + } + + public class InvalidVirtualPrivateAutoProperty : ValidClass + { + public virtual int NonVirtualSetterProperty + { + get; + private set; + } + } + + [Test] + public void PrivateSetterOnVirtualPropertyShouldThrows() + { + Assert.Throws<InvalidProxyTypeException>(() => Validate(typeof(InvalidVirtualPrivateAutoProperty))); + } } } Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -0,0 +1,104 @@ +using System; +using System.Reflection; +using NHibernate.Proxy; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.NHSpecificTest.ProxyValidator +{ + public class ShouldBeProxiableTests + { + private class MyClass: IDisposable + { + public void Dispose() + { + + } + } + private class ProtectedNoVirtualProperty + { + protected int Aprop { get; set; } + protected internal int AProtectedInternalProp { get; set; } + internal int AInternalProp { get; set; } + } + + private class NoVirtualMethods + { + protected void AProtected() { } + private void APrivate() { } + public void APublic() { } + internal void AInternal() { } + protected internal void AProtectedInternal() { } + } + + [Test] + public void GetTypeNotBeProxiable() + { + var method = typeof(object).GetMethod("GetType"); + method.ShouldBeProxiable().Should().Be.False(); + } + + [Test] + public void DisposeNotBeProxiable() + { + var method = typeof(MyClass).GetMethod("Dispose"); + method.ShouldBeProxiable().Should().Be.False(); + } + + [Test] + public void WhenProtectedNoVirtualPropertyThenShouldntBeProxiable() + { + var prop = typeof(ProtectedNoVirtualProperty).GetProperty("Aprop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + prop.ShouldBeProxiable().Should().Be.False(); + } + + [Test] + public void WhenProtectedInternalNoVirtualPropertyThenShouldBeProxiable() + { + var prop = typeof(ProtectedNoVirtualProperty).GetProperty("AProtectedInternalProp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + prop.ShouldBeProxiable().Should().Be.True(); + } + + [Test] + public void WhenInternalNoVirtualPropertyThenShouldBeProxiable() + { + var prop = typeof(ProtectedNoVirtualProperty).GetProperty("AInternalProp", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + prop.ShouldBeProxiable().Should().Be.True(); + } + + [Test] + public void WhenProtectedNoVirtualMethodThenShouldntBeProxiable() + { + var method = typeof(NoVirtualMethods).GetMethod("AProtected", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + method.ShouldBeProxiable().Should().Be.False(); + } + + [Test] + public void WhenProtectedInternalNoVirtualMethodThenShouldBeProxiable() + { + var method = typeof(NoVirtualMethods).GetMethod("AProtectedInternal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + method.ShouldBeProxiable().Should().Be.True(); + } + + [Test] + public void WhenPrivateMethodThenShouldntBeProxiable() + { + var method = typeof(NoVirtualMethods).GetMethod("APrivate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + method.ShouldBeProxiable().Should().Be.False(); + } + + [Test] + public void WhenPublicMethodThenShouldBeProxiable() + { + var method = typeof(NoVirtualMethods).GetMethod("APublic", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + method.ShouldBeProxiable().Should().Be.True(); + } + + [Test] + public void WhenInternalMethodThenShouldBeProxiable() + { + var method = typeof(NoVirtualMethods).GetMethod("AInternal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + method.ShouldBeProxiable().Should().Be.True(); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-18 21:24:23 UTC (rev 5718) @@ -769,6 +769,7 @@ <Compile Include="NHSpecificTest\Properties\CompositePropertyRefTest.cs" /> <Compile Include="NHSpecificTest\Properties\DynamicEntityTest.cs" /> <Compile Include="NHSpecificTest\Properties\Model.cs" /> + <Compile Include="NHSpecificTest\ProxyValidator\ShouldBeProxiableTests.cs" /> <Compile Include="NHSpecificTest\SqlConverterAndMultiQuery\Fixture.cs" /> <Compile Include="NHSpecificTest\SqlConverterAndMultiQuery\Model.cs" /> <Compile Include="NHSpecificTest\SqlConverterAndMultiQuery\SqlConverter.cs" /> Modified: trunk/nhibernate/src/NHibernate.Test/UtilityTest/ReflectionHelperIsMethodOfTests.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/UtilityTest/ReflectionHelperIsMethodOfTests.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/UtilityTest/ReflectionHelperIsMethodOfTests.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using NHibernate.Linq; +using NHibernate.Util; using NUnit.Framework; using SharpTestsEx; Modified: trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/ComplexDomain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/ComplexDomain.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/ComplexDomain.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -5,7 +5,7 @@ public class Bar { public virtual int Id { get; set; } - public virtual byte[] Timestamp { get; private set; } + public virtual byte[] Timestamp { get; protected set; } public virtual int AField { get; set; } public virtual Foo Foo { get; set; } } @@ -17,7 +17,7 @@ Bars = new HashedSet<Bar>(); } public virtual int Id { get; set; } - public virtual byte[] Timestamp { get; private set; } + public virtual byte[] Timestamp { get; protected set; } public virtual int AField { get; set; } public virtual ISet<Bar> Bars { get; set; } Modified: trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/SimpleVersioned.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/SimpleVersioned.cs 2011-04-18 17:25:00 UTC (rev 5717) +++ trunk/nhibernate/src/NHibernate.Test/VersionTest/Db/MsSQL/SimpleVersioned.cs 2011-04-18 21:24:23 UTC (rev 5718) @@ -2,8 +2,8 @@ { public class SimpleVersioned { - public virtual int Id { get; private set; } - public virtual byte[] LastModified { get; private set; } + public virtual int Id { get; protected set; } + public virtual byte[] LastModified { get; protected set; } public virtual string Something { get; set; } } } \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-18 17:25:07
|
Revision: 5717 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5717&view=rev Author: patearl Date: 2011-04-18 17:25:00 +0000 (Mon, 18 Apr 2011) Log Message: ----------- Linq: More changes related to NH-2583. Use a stack to help eliminate member variable leakage. Handle stand-alone boolean member and method call expressions. Eliminate an earlier invalid attempted fix. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-17 22:28:45 UTC (rev 5716) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-18 17:25:00 UTC (rev 5717) @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq.Expressions; using NHibernate.Linq.ReWriters; @@ -102,10 +103,10 @@ // The following is used for all *condition* traversal (but not *expressions* that are not conditions). // This is the "mapping" described in the text at NH-2583. - private Dictionary<string, int> _memberExpressionMapping = new Dictionary<string, int>(); + private Stack<Dictionary<string, int>> _memberExpressionMappings = new Stack<Dictionary<string, int>>(); // The following two are used for member expressions traversal. - private HashSet<string> _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + private Stack<HashSet<string>> _collectedPathMemberExpressionsInExpressions = new Stack<HashSet<string>>(); private int _memberExpressionDepth = 0; internal @@ -122,16 +123,16 @@ if (expression.NodeType == ExpressionType.AndAlso && expression.Type == typeof(bool)) { // Case (a) from the text at NH-2583. + _memberExpressionMappings.Push(new Dictionary<string, int>()); var newLeft = VisitExpression(expression.Left); + var leftMapping = _memberExpressionMappings.Pop(); - var leftMapping = _memberExpressionMapping; - + _memberExpressionMappings.Push(new Dictionary<string, int>()); var newRight = VisitExpression(expression.Right); + var rightMapping = _memberExpressionMappings.Pop(); - var rightMapping = _memberExpressionMapping; + BinaryMapping(_memberExpressionMappings.Peek(), leftMapping, rightMapping, AND); - _memberExpressionMapping = BinaryMapping(leftMapping, rightMapping, AND); - // The following is copy-pasted from Relinq's visitor, as I had to split the code above. var newConversion = (LambdaExpression)VisitExpression(expression.Conversion); if (newLeft != expression.Left || newRight != expression.Right || newConversion != expression.Conversion) @@ -140,16 +141,16 @@ else if (expression.NodeType == ExpressionType.OrElse && expression.Type == typeof(bool)) { // Case (b) + _memberExpressionMappings.Push(new Dictionary<string, int>()); var newLeft = VisitExpression(expression.Left); + var leftMapping = _memberExpressionMappings.Pop(); - var leftMapping = _memberExpressionMapping; - + _memberExpressionMappings.Push(new Dictionary<string, int>()); var newRight = VisitExpression(expression.Right); + var rightMapping = _memberExpressionMappings.Pop(); - var rightMapping = _memberExpressionMapping; + BinaryMapping(_memberExpressionMappings.Peek(), leftMapping, rightMapping, OR); - _memberExpressionMapping = BinaryMapping(leftMapping, rightMapping, OR); - // Again, the following is copy-pasted from Relinq's visitor, as I had to split the code above. var newConversion = (LambdaExpression)VisitExpression(expression.Conversion); if (newLeft != expression.Left || newRight != expression.Right || newConversion != expression.Conversion) @@ -164,63 +165,60 @@ || expression.NodeType == ExpressionType.GreaterThanOrEqual)) { // Cases (e), (f).2, (g).2 - _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); baseResult = base.VisitBinaryExpression(expression); - _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, N); + FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), N); } else if (expression.Type == typeof(bool) && expression.NodeType == ExpressionType.NotEqual) { // Case (h) - _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); baseResult = base.VisitBinaryExpression(expression); - _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, F); + FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), F); } else if (expression.Type == typeof(bool) && expression.NodeType == ExpressionType.Equal) { // Case (i) - _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); baseResult = base.VisitBinaryExpression(expression); - _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, T); + FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), T); } else // +, * etc. { // Case (j) - _collectedPathMemberExpressionsInExpression = new HashSet<string>(); - baseResult = base.VisitBinaryExpression(expression); - - _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, TNF); } return baseResult; } - private static Dictionary<string, int> FixedMapping(IEnumerable<string> collectedPathMemberExpressionsInExpression, int value) + private static void FixedMapping(Dictionary<string, int> resultMapping, IEnumerable<string> collectedPathMemberExpressionsInExpression, int value) { - var memberExpressionMapping = new Dictionary<string, int>(); foreach (var me in collectedPathMemberExpressionsInExpression) { - memberExpressionMapping.Add(me, value); + // This ORing behavior was added without much thought to fix NHibernate.Test.NHSpecificTest.NH2378.Fixture.ShortEntityCanBeQueryCorrectlyUsingLinqProvider. + if (resultMapping.ContainsKey(me)) + resultMapping[me] |= value; + else + resultMapping.Add(me, value); } - return memberExpressionMapping; } - private static Dictionary<string, int> BinaryMapping(Dictionary<string, int> leftMapping, Dictionary<string, int> rightMapping, int[,] op) + private static void BinaryMapping(Dictionary<string, int> resultMapping, Dictionary<string, int> leftMapping, Dictionary<string, int> rightMapping, int[,] op) { - var result = new Dictionary<string, int>(); // Compute mapping for all member expressions in leftMapping. If the member expression is missing // in rightMapping, use TNF as a "pessimistic approximation" instead (inside the ?: operator). See // the text for an explanation of this. foreach (var lhs in leftMapping) { - result.Add(lhs.Key, op[lhs.Value, rightMapping.ContainsKey(lhs.Key) ? rightMapping[lhs.Key] : TNF]); + resultMapping.Add(lhs.Key, op[lhs.Value, rightMapping.ContainsKey(lhs.Key) ? rightMapping[lhs.Key] : TNF]); } // Compute mapping for all member expressions *only* in rightMapping (we did the common ones above). // Again, use TNF as pessimistic approximation to result of left subcondition. @@ -228,10 +226,9 @@ { if (!leftMapping.ContainsKey(rhs.Key)) { - result[rhs.Key] = op[rhs.Value, TNF]; + resultMapping[rhs.Key] = op[rhs.Value, TNF]; } } - return result; } private static bool IsNullConstantExpression(Expression expression) @@ -255,14 +252,13 @@ if (expression.NodeType == ExpressionType.Not && expression.Type == typeof(bool)) { // Case (c) from text at NH-2583. + _memberExpressionMappings.Push(new Dictionary<string, int>()); baseResult = VisitExpression(expression.Operand); + var opMapping = _memberExpressionMappings.Pop(); - var opMapping = _memberExpressionMapping; - _memberExpressionMapping = new Dictionary<string, int>(); - foreach (var m in opMapping) { - _memberExpressionMapping.Add(m.Key, NOT[m.Value]); + _memberExpressionMappings.Peek().Add(m.Key, NOT[m.Value]); } } else @@ -286,63 +282,98 @@ // return expression; //} - protected override Expression VisitMemberExpression(MemberExpression expression) + protected override Expression VisitMethodCallExpression(MethodCallExpression expression) { - ArgumentUtility.CheckNotNull("expression", expression); + // Similar logic to VisitMemberExpression, but for handling boolean method results instead of boolean members. + bool addOwnMemberExpressionMapping = false; + if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0) + { + if (expression.Type != typeof(bool)) + throw new AssertionFailure("Was expected a boolean member expression."); + addOwnMemberExpressionMapping = true; + _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); + } - Expression newExpression; try { - _memberExpressionDepth++; - newExpression = base.VisitExpression(expression.Expression); + return base.VisitMethodCallExpression(expression); } finally { - _memberExpressionDepth--; + if (addOwnMemberExpressionMapping) + { + // Same mapping as the not-null (in)equality clause in VisitBinaryExpression. + FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), N); + } } - bool isEntity = _isEntityDecider.IsEntity(expression.Type); - - if (isEntity) - { - // See (h) why we do not check for _memberExpressionDepth here! - _collectedPathMemberExpressionsInExpression.Add(ExpressionKeyVisitor.Visit(expression, null)); - } + } - if (_memberExpressionDepth > 0 && isEntity) + protected override Expression VisitMemberExpression(MemberExpression expression) + { + ArgumentUtility.CheckNotNull("expression", expression); + + // For the boolean part of expressions like: a => a.B.C == 1 && a.D.E + // There wouldn't have been a parent operator to collect paths for a.D.E. + // Below we add the same mapping as if we were doing a.D.E == true. + bool addOwnMemberExpressionMapping = false; + if (_memberExpressionDepth == 0 && _collectedPathMemberExpressionsInExpressions.Count == 0) { - return AddJoin(expression); + if (expression.Type != typeof(bool)) + throw new AssertionFailure("Was expected a boolean member expression."); + addOwnMemberExpressionMapping = true; + _collectedPathMemberExpressionsInExpressions.Push(new HashSet<string>()); } - else - { - if (newExpression != expression.Expression) - return Expression.MakeMemberAccess(newExpression, expression.Member); - return expression; - } - } - protected override Expression VisitConstantExpression(ConstantExpression expression) - { - if (expression.Type == typeof(bool)) + try { - if ((bool)expression.Value) + Expression newExpression; + try { - _memberExpressionMapping = FixedMapping(new string[0], T); + _memberExpressionDepth++; + newExpression = base.VisitExpression(expression.Expression); } + finally + { + _memberExpressionDepth--; + } + bool isEntity = _isEntityDecider.IsEntity(expression.Type); + + if (isEntity) + { + // See (h) why we do not check for _memberExpressionDepth here! + _collectedPathMemberExpressionsInExpressions.Peek().Add(ExpressionKeyVisitor.Visit(expression, null)); + } + + if (_memberExpressionDepth > 0 && isEntity) + { + return AddJoin(expression); + } else { - _memberExpressionMapping = FixedMapping(new string[0], F); + if (newExpression != expression.Expression) + return Expression.MakeMemberAccess(newExpression, expression.Member); + return expression; } } - return expression; + finally + { + if (addOwnMemberExpressionMapping) + { + // Same mapping as the not-null (in)equality clause in VisitBinaryExpression. + FixedMapping(_memberExpressionMappings.Peek(), _collectedPathMemberExpressionsInExpressions.Pop(), N); + } + } } internal static void Find(Expression expression, NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) { WhereJoinDetector f = new WhereJoinDetector(nameGenerator, isEntityDecider, joins, expressionMap); + f._memberExpressionMappings.Push(new Dictionary<string, int>()); + f.VisitExpression(expression); - foreach (var mapping in f._memberExpressionMapping) + foreach (var mapping in f._memberExpressionMappings.Pop()) { // If outer join can never produce true, we can safely inner join. if ((mapping.Value & T) == 0) @@ -351,6 +382,5 @@ } } } - } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-17 22:28:51
|
Revision: 5716 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5716&view=rev Author: patearl Date: 2011-04-17 22:28:45 +0000 (Sun, 17 Apr 2011) Log Message: ----------- Linq: Member join test improvements and a bug fix. (NH-2583 again) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingNotAndDeMorganFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOneOrTreeFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOrderByFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingSelectFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingThreeOrTreesSideBySideFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingTwoOrTreesSideBySideFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/SelfJoinTestFixture.cs Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -320,6 +320,22 @@ } } + protected override Expression VisitConstantExpression(ConstantExpression expression) + { + if (expression.Type == typeof(bool)) + { + if ((bool)expression.Value) + { + _memberExpressionMapping = FixedMapping(new string[0], T); + } + else + { + _memberExpressionMapping = FixedMapping(new string[0], F); + } + } + return expression; + } + internal static void Find(Expression expression, NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) { WhereJoinDetector f = new WhereJoinDetector(nameGenerator, isEntityDecider, joins, expressionMap); Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -87,7 +87,7 @@ } - protected void RunTest<T1, T2, T3, T4, T5, T6, T7>(Expression<Func<MyBO, bool>> condition, SetterTuple<T1, T2, T3, T4, T5, T6, T7> setters) + protected int RunTest<T1, T2, T3, T4, T5, T6, T7>(Expression<Func<MyBO, bool>> condition, SetterTuple<T1, T2, T3, T4, T5, T6, T7> setters) { if (condition == null) { @@ -119,7 +119,7 @@ { using (session.BeginTransaction()) { - TestAndAssert(condition, session, expectedIds); + return TestAndAssert(condition, session, expectedIds); } } @@ -141,7 +141,7 @@ } } - protected abstract void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds); + protected abstract int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds); protected static SetterTuple<T1, T2, T3, T4, T5, T6, T7> Setters<T1, T2, T3, T4, T5, T6, T7>(Action<MyBO, ISession, T1> set1, Action<MyBO, ISession, T2> set2, Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -13,7 +13,6 @@ /// This setup is used in most tests in here - but not all; and we might want to /// twist it for special tests. Therefore, the OnSetUp mechanism is not used. /// </summary> - [Test] private void StandardSetUp() { using (var session = OpenSession()) @@ -49,6 +48,7 @@ } } + [Test] public void OrWithTrueShouldBeEqualToTrue() { StandardSetUp(); Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingNotAndDeMorganFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingNotAndDeMorganFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingNotAndDeMorganFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -9,38 +9,41 @@ { public class MassTestingNotAndDeMorganFixture : AbstractMassTestingFixture { - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { var result = session.Query<MyBO>().Where(condition); AreEqual(expectedIds, result.Select(bo => bo.Id).ToArray()); + return expectedIds.Count(); } [Test] - public void Test_NotUnequalIsNotTheSameAsEqual() + public void Test_NotUnequalIsTheSameAsEqual() { - RunTest(x => !(x.BO1.I1 != 1), - Setters<TBO1_I>(MyBO.SetBO1_I1)); - // ... is the same as ... - RunTest(x => !(x.BO1.I1 != 1), - Setters<TBO1_I>(MyBO.SetBO1_I1)); - // ... is NOT the same as ... - RunTest(x => x.BO1.I1 == 1, - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); - // The latter returns fewer results! - namely NOT the ones where BO1 is null. + int r1 = RunTest(x => !(x.BO1.I1 != 1), + Setters<TBO1_I>(MyBO.SetBO1_I1)); + int r2 = RunTest(x => x.BO1.I1 == 1, + Setters<TBO1_I>(MyBO.SetBO1_I1)); + Assert.AreEqual(r1, r2); + Assert.Greater(r1, 0); + + r1 = RunTest(x => !(x.BO1.I1 != 1), + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + r2 = RunTest(x => x.BO1.I1 == 1, + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + Assert.AreEqual(r1, r2); + Assert.Greater(r1, 0); } [Test] - public void Test_NotEqualIsNotTheSameAsNotequal() + public void Test_NotEqualIsTheSameAsNotequal() { - RunTest(x => !(x.BO1.I1 == 1), - Setters<TBO1_I>(MyBO.SetBO1_I1)); + int r1 = RunTest(x => !(x.BO1.I1 == 1), + Setters<TBO1_I>(MyBO.SetBO1_I1)); // ... is the same as ... - RunTest(x => !(x.BO1.I1 == 1), - Setters<TBO1_I>(MyBO.SetBO1_I1)); - // ... is NOT the same as ... - RunTest(x => x.BO1.I1 != 1, - Setters<TBO1_I>(MyBO.SetBO1_I1)); - // As before, the latter returns fewer results! - namely NOT the ones where BO1 is null. + int r2 = RunTest(x => x.BO1.I1 != 1, + Setters<TBO1_I>(MyBO.SetBO1_I1)); + Assert.AreEqual(r1, r2); + Assert.Greater(r1, 0); } [Test] @@ -64,22 +67,25 @@ [Test] public void Test_DeMorganNotOr() { - RunTest(x => !(x.BO1.I1 != 1 || x.BO2.J1 != 1), - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); - RunTest(x => !(x.BO1.I1 != 1 || x.BO2.J1 != 1), - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); - RunTest(x => !(x.BO1.I1 != 1) && !(x.BO2.J1 != 1), - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); - // ... is NOT the same as ... - RunTest(x => x.BO1.I1 == 1 && x.BO2.J1 == 1, - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + int r1 = RunTest(x => !(x.BO1.I1 != 1 || x.BO2.J1 != 1), + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + int r2 = RunTest(x => !(x.BO1.I1 != 1) && !(x.BO2.J1 != 1), + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + int r3 = RunTest(x => x.BO1.I1 == 1 && x.BO2.J1 == 1, + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + Assert.AreEqual(r1, r2); + Assert.AreEqual(r2, r3); + Assert.Greater(r1, 0); } [Test] public void Test_NotNotCanBeEliminated() { - RunTest(x => !(!(x.BO1.I1 != 1 && x.BO2.J1 != 1)), - Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + int r1 = RunTest(x => !(!(x.BO1.I1 != 1 && x.BO2.J1 != 1)), + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + int r2 = RunTest(x => x.BO1.I1 != 1 && x.BO2.J1 != 1, + Setters<TBO1_I, TBO2_J>(MyBO.SetBO1_I1, MyBO.SetBO2_J1)); + Assert.AreEqual(r1, r2); } } } Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOneOrTreeFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOneOrTreeFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOneOrTreeFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -9,10 +9,11 @@ { public class MassTestingOneOrTreeFixture : AbstractMassTestingFixture { - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { var result = session.Query<MyBO>().Where(condition); AreEqual(expectedIds, result.Select(bo => bo.Id).ToArray()); + return expectedIds.Count(); } // Condition pattern: (A && B) && (C || D) Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOrderByFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOrderByFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOrderByFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -9,13 +9,15 @@ { public class MassTestingOrderByFixture : AbstractMassTestingFixture { - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { IQueryable<MyBO> result = session.Query<MyBO>().Where(condition).OrderByDescending(bo => bo.BO1.I1 ?? bo.BO1.Id); var forceDBRun = result.ToList(); AreEqual(expectedIds, forceDBRun.Select(bo => bo.Id).ToArray()); + + return expectedIds.Count(); } // Condition pattern: (A && B) && (C || D) ORDER BY F @@ -66,7 +68,7 @@ Setters<TK, TK, TBO1_I, TK>(MyBO.SetK1, MyBO.SetK2, MyBO.SetBO1_I1, MyBO.SetK3)); } - [Test, Ignore("RED!")] // TODO: Analyze and repair! + [Test] public void Test_xyP_in_C_F____xy_OJ() { RunTest(x => (x.K1 == 1 && x.K1 == 1) && (x.BO1.Id > 0 && x.K2 == 1 || x.K3 == 1), Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingSelectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingSelectFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingSelectFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -9,7 +9,7 @@ { public class MassTestingSelectFixture : AbstractMassTestingFixture { - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { IQueryable<int?> result = session.Query<MyBO>().Where(condition).Select(bo => (int?) bo.BO1.Id); @@ -19,6 +19,9 @@ var expectedBO1Ids = session.Query<MyBO>().Where(bo => expectedIds.Contains(bo.Id)).Select(bo => bo.BO1 == null ? 0 : bo.BO1.Id).ToList(); AreEqual(expectedBO1Ids, resultNullTo0.ToArray()); + + // Unused result. + return -1; } // Condition pattern: (A && B) && (C || D) SELECT E @@ -69,7 +72,7 @@ Setters<TK, TK, TBO1_I, TK>(MyBO.SetK1, MyBO.SetK2, MyBO.SetBO1_I1, MyBO.SetK3)); } - [Test, Ignore("RED!")] // TODO: Analyze and repair! + [Test] public void Test_xyP_in_C_E____xy_OJ() { RunTest(x => (x.K1 == 1 && x.K1 == 1) && (x.BO1.Id > 0 && x.K2 == 1 || x.K3 == 1), Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingThreeOrTreesSideBySideFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingThreeOrTreesSideBySideFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingThreeOrTreesSideBySideFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -11,14 +11,17 @@ { protected void RunTest<T1, T2, T3, T4, T5, T6, T7>(Expression<Func<MyBO, bool>> c1, Expression<Func<MyBO, bool>> c2, SetterTuple<T1, T2, T3, T4, T5, T6, T7> setters) { - RunTest(c1, setters); - RunTest(c2, setters); + int r1 = RunTest(c1, setters); + int r2 = RunTest(c2, setters); + Assert.AreEqual(r1, r2); + Assert.Greater(r1, 0); } - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { var result = session.Query<MyBO>().Where(condition); AreEqual(expectedIds, result.Select(bo => bo.Id).ToArray()); + return expectedIds.Count(); } // Condition pattern: (A || B) || (C || D), A || (B || (C || D)) Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingTwoOrTreesSideBySideFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingTwoOrTreesSideBySideFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingTwoOrTreesSideBySideFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -9,10 +9,11 @@ { public class MassTestingTwoOrTreesSideBySideFixture : AbstractMassTestingFixture { - protected override void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) + protected override int TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds) { var result = session.Query<MyBO>().Where(condition); AreEqual(expectedIds, result.Select(bo => bo.Id).ToArray()); + return expectedIds.Count(); } // Condition pattern: (A || B) && (C || D) Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/SelfJoinTestFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/SelfJoinTestFixture.cs 2011-04-17 12:03:53 UTC (rev 5715) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/SelfJoinTestFixture.cs 2011-04-17 22:28:45 UTC (rev 5716) @@ -54,7 +54,8 @@ where bo.LeftSon.LeftSon.K1 == null || bo.RightSon.RightSon.K1 == null select bo).ToList().Select(bo => bo.Name); - //Assert.That(() => result.ToList(), Is.EquivalentTo(new[] { "1", "2", "3", ...and many more... })); + Assert.That(!result.Contains("1")); + Assert.That(result.Count(), Is.EqualTo(18)); } } @@ -67,7 +68,8 @@ where bo.LeftSon.K1 == null || bo.RightSon.K1 == null select bo).ToList().Select(bo => bo.Name); - //Assert.That(() => result.ToList(), Is.EquivalentTo(new[] { "1", "1L", "1R", "2", "2L", "2R", "3", "3L", "4", ...and many more... })); + Assert.That(!result.Contains("1")); + Assert.That(result.Count(), Is.EqualTo(18)); } } @@ -78,11 +80,11 @@ using (var tx = session.BeginTransaction()) { { - var bLeftLeft = new MyBO { Id = 111, Name = "1LL", K2 = 1 }; + var bLeftLeft = new MyBO { Id = 111, Name = "1LL", K2 = 1, K1 = 1 }; var bLeftRight = new MyBO { Id = 112, Name = "1LR", K2 = 1 }; - var bLeft = new MyBO { Id = 11, Name = "1L", LeftSon = bLeftLeft, RightSon = bLeftRight }; - var bRightRight = new MyBO { Id = 122, Name = "1RR", K2 = 1 }; - var bRight = new MyBO { Id = 12, Name = "1R", RightSon = bRightRight }; + var bLeft = new MyBO { Id = 11, Name = "1L", LeftSon = bLeftLeft, RightSon = bLeftRight, K1 = 1 }; + var bRightRight = new MyBO { Id = 122, Name = "1RR", K2 = 1, K1 = 1 }; + var bRight = new MyBO { Id = 12, Name = "1R", RightSon = bRightRight, K1 = 1 }; var bRoot = new MyBO { Id = 1, Name = "1", LeftSon = bLeft, RightSon = bRight }; session.Save(bLeftLeft); session.Save(bLeftRight); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-17 12:04:00
|
Revision: 5715 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5715&view=rev Author: fabiomaulo Date: 2011-04-17 12:03:53 +0000 (Sun, 17 Apr 2011) Log Message: ----------- release notes Modified Paths: -------------- trunk/nhibernate/releasenotes.txt Modified: trunk/nhibernate/releasenotes.txt =================================================================== --- trunk/nhibernate/releasenotes.txt 2011-04-17 11:49:43 UTC (rev 5714) +++ trunk/nhibernate/releasenotes.txt 2011-04-17 12:03:53 UTC (rev 5715) @@ -7,7 +7,25 @@ * [NH-2593] - Form Microsoft SQL Server the default batch-size (adonet.batch_size) is set to 20 where not explicit defined in the session-factory configuration * - ICollectionPersister added property to fix [NH-2489] * [NH-2605] Refactorize MultiQuery/MultiCriteria implementation to delegate responsibility to IDrive (IDrive changed). +Build 3.2.0.Aplha2 (rev5715) +============================= +** Bug + * [NH-2540] - Linq generates invalid boolean case statements (was: Linq ignoring configured query-substitutions) + * [NH-2640] - HQL Having clause is ignored without preceeding group by + * [NH-2641] - HQL does not throw exception on unexpected trailing tokens + * [NH-2642] - BatcherDataReaderWrapper.GetValue has a typo + * [NH-2643] - MSSQL configuration template is still using "use_outer_join" + * [NH-2652] - SchemaMetadataUpdater does not take Dialect default properties +** Improvement + * [NH-2644] - schemaaction is not supported in joinedsubclass + +** New Feature + * [NH-2533] - Support paging in HQL + +** Task + * [NH-2653] - Remove just added ExpressionTreeVisitor class + Build 3.2.0.Aplha1 (rev5664) ============================= ** Bug This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-17 11:49:49
|
Revision: 5714 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5714&view=rev Author: fabiomaulo Date: 2011-04-17 11:49:43 +0000 (Sun, 17 Apr 2011) Log Message: ----------- Preparing release Modified Paths: -------------- trunk/nhibernate/build-common/common.xml Modified: trunk/nhibernate/build-common/common.xml =================================================================== --- trunk/nhibernate/build-common/common.xml 2011-04-16 22:07:50 UTC (rev 5713) +++ trunk/nhibernate/build-common/common.xml 2011-04-17 11:49:43 UTC (rev 5714) @@ -84,7 +84,7 @@ effectively SP0). --> - <property name="project.version" value="3.2.0.Alpha1" overwrite="false" /> + <property name="project.version" value="3.2.0.Alpha2" overwrite="false" /> <!-- Compute short project version (major.minor) using a regex --> <regex input="${project.version}" pattern="^(?'shortversion'\d+\.\d+)" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 22:07:56
|
Revision: 5713 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5713&view=rev Author: fabiomaulo Date: 2011-04-16 22:07:50 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Refactoring (removed duplicated code) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-16 21:27:47 UTC (rev 5712) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/ModelMapper.cs 2011-04-16 22:07:50 UTC (rev 5713) @@ -1598,14 +1598,18 @@ public void AddMapping<T>() where T: IConformistHoldersProvider, new() { - var mapping = new T(); + AddMapping(new T()); + } + + public void AddMapping(IConformistHoldersProvider mapping) + { var thisCustomizerHolder = customizerHolder as CustomizersHolder; if (thisCustomizerHolder == null) { throw new NotSupportedException("To merge 'conformist' mappings, the instance of ICustomizersHolder, provided in the ModelMapper constructor, have to be a CustomizersHolder instance."); } var otherCustomizerHolder = mapping.CustomizersHolder as CustomizersHolder; - if(otherCustomizerHolder == null) + if (otherCustomizerHolder == null) { throw new NotSupportedException("The mapping class have to provide a CustomizersHolder instance."); } @@ -1630,18 +1634,7 @@ { throw new ArgumentOutOfRangeException("type", "The mapping class must be an implementation of IConformistHoldersProvider."); } - var thisCustomizerHolder = customizerHolder as CustomizersHolder; - if (thisCustomizerHolder == null) - { - throw new NotSupportedException("To merge 'conformist' mappings, the instance of ICustomizersHolder, provided in the ModelMapper constructor, have to be a CustomizersHolder instance."); - } - var otherCustomizerHolder = mapping.CustomizersHolder as CustomizersHolder; - if (otherCustomizerHolder == null) - { - throw new NotSupportedException("The mapping class have to provide a CustomizersHolder instance."); - } - thisCustomizerHolder.Merge(otherCustomizerHolder); - explicitDeclarationsHolder.Merge(mapping.ExplicitDeclarationsHolder); + AddMapping(mapping); } public void AddMappings(IEnumerable<System.Type> types) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 21:27:53
|
Revision: 5712 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5712&view=rev Author: fabiomaulo Date: 2011-04-16 21:27:47 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Minor (simplified API) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs 2011-04-16 18:26:30 UTC (rev 5711) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/IPlainPropertyContainerMapper.cs 2011-04-16 21:27:47 UTC (rev 5712) @@ -27,6 +27,7 @@ void Component<TComponent>(Expression<Func<TContainer, TComponent>> property, Action<IComponentMapper<TComponent>> mapping) where TComponent : class; + void Component<TComponent>(Expression<Func<TContainer, TComponent>> property) where TComponent : class; void ManyToOne<TProperty>(Expression<Func<TContainer, TProperty>> property, Action<IManyToOneMapper> mapping) where TProperty : class; void ManyToOne<TProperty>(Expression<Func<TContainer, TProperty>> property) where TProperty : class; Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs 2011-04-16 18:26:30 UTC (rev 5711) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/PropertyContainerCustomizer.cs 2011-04-16 21:27:47 UTC (rev 5712) @@ -64,6 +64,10 @@ { RegisterComponentMapping(property, mapping); } + public void Component<TComponent>(Expression<Func<TEntity, TComponent>> property) where TComponent : class + { + RegisterComponentMapping(property, x => { }); + } protected virtual void RegisterComponentMapping<TComponent>(Expression<Func<TEntity, TComponent>> property, Action<IComponentMapper<TComponent>> mapping) where TComponent : class Modified: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs 2011-04-16 18:26:30 UTC (rev 5711) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs 2011-04-16 21:27:47 UTC (rev 5712) @@ -29,7 +29,7 @@ map.Column("MyClassId"); map.Generator(Generators.HighLow); }); - Component(x => x.Name, z => { }); + Component(x => x.Name); } } private class NameMap : ComponentMapping<Name> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 18:26:36
|
Revision: 5711 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5711&view=rev Author: fabiomaulo Date: 2011-04-16 18:26:30 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Conformist component registration fix Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/ComponentCustomizer.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/ComponentCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/ComponentCustomizer.cs 2011-04-16 18:12:44 UTC (rev 5710) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/ComponentCustomizer.cs 2011-04-16 18:26:30 UTC (rev 5711) @@ -4,7 +4,7 @@ namespace NHibernate.Mapping.ByCode.Impl.CustomizersImpl { - public class ComponentCustomizer<TComponent> : PropertyContainerCustomizer<TComponent>, IComponentMapper<TComponent> + public class ComponentCustomizer<TComponent> : PropertyContainerCustomizer<TComponent>, IComponentMapper<TComponent>, IConformistHoldersProvider where TComponent : class { public ComponentCustomizer(IModelExplicitDeclarationsHolder explicitDeclarationsHolder, ICustomizersHolder customizersHolder) @@ -96,5 +96,19 @@ CustomizersHolder.AddCustomizer(PropertyPath, classCustomizer); } } + + #region IConformistHoldersProvider Members + + ICustomizersHolder IConformistHoldersProvider.CustomizersHolder + { + get { return CustomizersHolder; } + } + + IModelExplicitDeclarationsHolder IConformistHoldersProvider.ExplicitDeclarationsHolder + { + get { return ExplicitDeclarationsHolder; } + } + + #endregion } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/ComponentMappingRegistrationTest.cs 2011-04-16 18:26:30 UTC (rev 5711) @@ -0,0 +1,80 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Conformist; +using NUnit.Framework; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ExpliticMappingTests.ConformistMappingRegistrationTests +{ + public class ComponentMappingRegistrationTest + { + public class MyClass + { + public int Id { get; set; } + public Name Name { get; set; } + } + + public class Name + { + public string First { get; set; } + public string Last { get; set; } + } + private class MyClassMap : ClassMapping<MyClass> + { + public MyClassMap() + { + Id(x => x.Id, map => + { + map.Column("MyClassId"); + map.Generator(Generators.HighLow); + }); + Component(x => x.Name, z => { }); + } + } + private class NameMap : ComponentMapping<Name> + { + public NameMap() + { + Property(x => x.First, map => map.Length(20)); + Property(x => x.Last, map => map.Length(30)); + } + } + + [Test] + public void WhenRegisterClassMappingThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping<MyClassMap>(); + mapper.AddMapping<NameMap>(); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(MyClass) }); + + ModelIsWellFormed(hbmMapping); + } + + [Test] + public void WhenRegisterClassMappingThroughTypeThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping(typeof(MyClassMap)); + mapper.AddMapping(typeof(NameMap)); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(MyClass) }); + + ModelIsWellFormed(hbmMapping); + } + + private void ModelIsWellFormed(HbmMapping hbmMapping) + { + var hbmClass = hbmMapping.RootClasses.Single(); + hbmClass.Properties.Should().Have.Count.EqualTo(1); + var hbmComponent = hbmClass.Properties.OfType<HbmComponent>().Single(); + hbmComponent.name.Should().Be("Name"); + hbmComponent.Properties.Should().Have.Count.EqualTo(2); + var hbmp1 = hbmComponent.Properties.OfType<HbmProperty>().Single(x => x.name == "First"); + var hbmp2 = hbmComponent.Properties.OfType<HbmProperty>().Single(x => x.name == "Last"); + + hbmp1.length.Should().Be("20"); + hbmp2.length.Should().Be("30"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:12:44 UTC (rev 5710) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:26:30 UTC (rev 5711) @@ -529,6 +529,7 @@ <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\SubclassSequenceRegistrationTests.cs" /> <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassMappingStrategyTests.cs" /> <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassSequenceRegistrationTests.cs" /> + <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\ComponentMappingRegistrationTest.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\JoinedSubclassMappingRegistration.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\ModelMapperAddMappingByTypeTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\SubclassMappingRegistration.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 18:12:50
|
Revision: 5710 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5710&view=rev Author: fabiomaulo Date: 2011-04-16 18:12:44 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Conformist union-subclass registration fix Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/UnionSubclassCustomizer.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/UnionSubclassMappingRegistrationTest.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/UnionSubclassCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/UnionSubclassCustomizer.cs 2011-04-16 18:09:08 UTC (rev 5709) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/UnionSubclassCustomizer.cs 2011-04-16 18:12:44 UTC (rev 5710) @@ -3,7 +3,7 @@ namespace NHibernate.Mapping.ByCode.Impl.CustomizersImpl { - public class UnionSubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, IUnionSubclassMapper<TEntity> where TEntity : class + public class UnionSubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, IUnionSubclassMapper<TEntity>, IConformistHoldersProvider where TEntity : class { public UnionSubclassCustomizer(IModelExplicitDeclarationsHolder explicitDeclarationsHolder, ICustomizersHolder customizersHolder) : base(explicitDeclarationsHolder, customizersHolder, null) @@ -111,5 +111,19 @@ } #endregion + + #region IConformistHoldersProvider Members + + ICustomizersHolder IConformistHoldersProvider.CustomizersHolder + { + get { return CustomizersHolder; } + } + + IModelExplicitDeclarationsHolder IConformistHoldersProvider.ExplicitDeclarationsHolder + { + get { return ExplicitDeclarationsHolder; } + } + + #endregion } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/UnionSubclassMappingRegistrationTest.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/UnionSubclassMappingRegistrationTest.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/UnionSubclassMappingRegistrationTest.cs 2011-04-16 18:12:44 UTC (rev 5710) @@ -0,0 +1,74 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Conformist; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ExpliticMappingTests.ConformistMappingRegistrationTests +{ + public class UnionSubclassMappingRegistrationTest + { + public class MyClass + { + public int Id { get; set; } + public string Something { get; set; } + } + public class Inherited : MyClass + { + public string SomethingElse { get; set; } + } + + private class MyClassMap : ClassMapping<MyClass> + { + public MyClassMap() + { + Id(x => x.Id, map => + { + map.Column("MyClassId"); + map.Generator(Generators.HighLow); + }); + Property(x => x.Something, map => map.Length(150)); + } + } + private class InheritedMap : UnionSubclassMapping<Inherited> + { + public InheritedMap() + { + Property(x => x.SomethingElse, map => map.Length(15)); + } + } + + [Test] + public void WhenRegisterClassMappingThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping<MyClassMap>(); + mapper.AddMapping<InheritedMap>(); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + [Test] + public void WhenRegisterClassMappingThroughTypeThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping(typeof(MyClassMap)); + mapper.AddMapping(typeof(InheritedMap)); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + private void ModelIsWellFormed(HbmMapping hbmMapping) + { + var hbmClass = hbmMapping.UnionSubclasses.Single(); + hbmClass.Should().Not.Be.Null(); + hbmClass.extends.Should().Contain("MyClass"); + var hbmProperty = hbmClass.Properties.OfType<HbmProperty>().Single(); + hbmProperty.name.Should().Be("SomethingElse"); + hbmProperty.length.Should().Be("15"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:09:08 UTC (rev 5709) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:12:44 UTC (rev 5710) @@ -532,6 +532,7 @@ <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\JoinedSubclassMappingRegistration.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\ModelMapperAddMappingByTypeTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\SubclassMappingRegistration.cs" /> + <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\UnionSubclassMappingRegistrationTest.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\IdBagMappingTest.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\MappingOfPrivateMembersOnRootEntity.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\NaturalIdTests.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 18:09:14
|
Revision: 5709 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5709&view=rev Author: fabiomaulo Date: 2011-04-16 18:09:08 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Conformist joined-subclass registration fix Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/JoinedSubclassCustomizer.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/JoinedSubclassMappingRegistration.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/JoinedSubclassCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/JoinedSubclassCustomizer.cs 2011-04-16 18:04:59 UTC (rev 5708) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/JoinedSubclassCustomizer.cs 2011-04-16 18:09:08 UTC (rev 5709) @@ -3,7 +3,7 @@ namespace NHibernate.Mapping.ByCode.Impl.CustomizersImpl { - public class JoinedSubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, IJoinedSubclassMapper<TEntity> where TEntity : class + public class JoinedSubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, IJoinedSubclassMapper<TEntity>, IConformistHoldersProvider where TEntity : class { private readonly IKeyMapper<TEntity> keyMapper; @@ -125,5 +125,19 @@ } #endregion + + #region IConformistHoldersProvider Members + + ICustomizersHolder IConformistHoldersProvider.CustomizersHolder + { + get { return CustomizersHolder; } + } + + IModelExplicitDeclarationsHolder IConformistHoldersProvider.ExplicitDeclarationsHolder + { + get { return ExplicitDeclarationsHolder; } + } + + #endregion } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/JoinedSubclassMappingRegistration.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/JoinedSubclassMappingRegistration.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/JoinedSubclassMappingRegistration.cs 2011-04-16 18:09:08 UTC (rev 5709) @@ -0,0 +1,74 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Conformist; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ExpliticMappingTests.ConformistMappingRegistrationTests +{ + public class JoinedSubclassMappingRegistration + { + public class MyClass + { + public int Id { get; set; } + public string Something { get; set; } + } + public class Inherited : MyClass + { + public string SomethingElse { get; set; } + } + + private class MyClassMap : ClassMapping<MyClass> + { + public MyClassMap() + { + Id(x => x.Id, map => + { + map.Column("MyClassId"); + map.Generator(Generators.HighLow); + }); + Property(x => x.Something, map => map.Length(150)); + } + } + private class InheritedMap : JoinedSubclassMapping<Inherited> + { + public InheritedMap() + { + Property(x => x.SomethingElse, map => map.Length(15)); + } + } + + [Test] + public void WhenRegisterClassMappingThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping<MyClassMap>(); + mapper.AddMapping<InheritedMap>(); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + [Test] + public void WhenRegisterClassMappingThroughTypeThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping(typeof(MyClassMap)); + mapper.AddMapping(typeof(InheritedMap)); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + private void ModelIsWellFormed(HbmMapping hbmMapping) + { + var hbmClass = hbmMapping.JoinedSubclasses.Single(); + hbmClass.Should().Not.Be.Null(); + hbmClass.extends.Should().Contain("MyClass"); + var hbmProperty = hbmClass.Properties.OfType<HbmProperty>().Single(); + hbmProperty.name.Should().Be("SomethingElse"); + hbmProperty.length.Should().Be("15"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:04:59 UTC (rev 5708) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:09:08 UTC (rev 5709) @@ -529,6 +529,7 @@ <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\SubclassSequenceRegistrationTests.cs" /> <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassMappingStrategyTests.cs" /> <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassSequenceRegistrationTests.cs" /> + <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\JoinedSubclassMappingRegistration.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\ModelMapperAddMappingByTypeTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\SubclassMappingRegistration.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\IdBagMappingTest.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2011-04-16 18:05:05
|
Revision: 5708 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5708&view=rev Author: fabiomaulo Date: 2011-04-16 18:04:59 +0000 (Sat, 16 Apr 2011) Log Message: ----------- Conformist subclass registration fix Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/SubclassCustomizer.cs trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/SubclassMappingRegistration.cs Modified: trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/SubclassCustomizer.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/SubclassCustomizer.cs 2011-04-15 23:55:13 UTC (rev 5707) +++ trunk/nhibernate/src/NHibernate/Mapping/ByCode/Impl/CustomizersImpl/SubclassCustomizer.cs 2011-04-16 18:04:59 UTC (rev 5708) @@ -4,7 +4,7 @@ namespace NHibernate.Mapping.ByCode.Impl.CustomizersImpl { - public class SubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, ISubclassMapper<TEntity> where TEntity : class + public class SubclassCustomizer<TEntity> : PropertyContainerCustomizer<TEntity>, ISubclassMapper<TEntity>, IConformistHoldersProvider where TEntity : class { private Dictionary<string, IJoinMapper<TEntity>> joinCustomizers; @@ -123,5 +123,19 @@ } #endregion + + #region IConformistHoldersProvider Members + + ICustomizersHolder IConformistHoldersProvider.CustomizersHolder + { + get { return CustomizersHolder; } + } + + IModelExplicitDeclarationsHolder IConformistHoldersProvider.ExplicitDeclarationsHolder + { + get { return ExplicitDeclarationsHolder; } + } + + #endregion } } \ No newline at end of file Added: trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/SubclassMappingRegistration.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/SubclassMappingRegistration.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/MappingByCode/ExpliticMappingTests/ConformistMappingRegistrationTests/SubclassMappingRegistration.cs 2011-04-16 18:04:59 UTC (rev 5708) @@ -0,0 +1,74 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using NHibernate.Mapping.ByCode; +using NHibernate.Mapping.ByCode.Conformist; +using SharpTestsEx; + +namespace NHibernate.Test.MappingByCode.ExpliticMappingTests.ConformistMappingRegistrationTests +{ + public class SubclassMappingRegistration + { + public class MyClass + { + public int Id { get; set; } + public string Something { get; set; } + } + public class Inherited: MyClass + { + public string SomethingElse { get; set; } + } + + private class MyClassMap: ClassMapping<MyClass> + { + public MyClassMap() + { + Id(x => x.Id, map => + { + map.Column("MyClassId"); + map.Generator(Generators.HighLow); + }); + Property(x => x.Something, map => map.Length(150)); + } + } + private class InheritedMap : SubclassMapping<Inherited> + { + public InheritedMap() + { + Property(x => x.SomethingElse, map => map.Length(15)); + } + } + + [Test] + public void WhenRegisterClassMappingThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping<MyClassMap>(); + mapper.AddMapping<InheritedMap>(); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + [Test] + public void WhenRegisterClassMappingThroughTypeThenMapTheClass() + { + var mapper = new ModelMapper(); + mapper.AddMapping(typeof(MyClassMap)); + mapper.AddMapping(typeof(InheritedMap)); + var hbmMapping = mapper.CompileMappingFor(new[] { typeof(Inherited) }); + + ModelIsWellFormed(hbmMapping); + } + + private void ModelIsWellFormed(HbmMapping hbmMapping) + { + var hbmClass = hbmMapping.SubClasses.Single(); + hbmClass.Should().Not.Be.Null(); + hbmClass.extends.Should().Contain("MyClass"); + var hbmProperty = hbmClass.Properties.OfType<HbmProperty>().Single(); + hbmProperty.name.Should().Be("SomethingElse"); + hbmProperty.length.Should().Be("15"); + } + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-15 23:55:13 UTC (rev 5707) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj 2011-04-16 18:04:59 UTC (rev 5708) @@ -530,6 +530,7 @@ <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassMappingStrategyTests.cs" /> <Compile Include="MappingByCode\ExplicitlyDeclaredModelTests\UnionSubclassSequenceRegistrationTests.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\ModelMapperAddMappingByTypeTests.cs" /> + <Compile Include="MappingByCode\ExpliticMappingTests\ConformistMappingRegistrationTests\SubclassMappingRegistration.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\IdBagMappingTest.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\MappingOfPrivateMembersOnRootEntity.cs" /> <Compile Include="MappingByCode\ExpliticMappingTests\NaturalIdTests.cs" /> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-15 23:55:20
|
Revision: 5707 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5707&view=rev Author: patearl Date: 2011-04-15 23:55:13 +0000 (Fri, 15 Apr 2011) Log Message: ----------- Linq: More changes related to NH-2583. (Also includes a trivial compilation fix to an earlier commit) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetectorDesignNotes.txt Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Linq/Clauses/LeftJoinClause.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddLeftJoinsReWriter.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/LeftJoinDetector.cs Deleted: trunk/nhibernate/src/NHibernate/Linq/Clauses/LeftJoinClause.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Clauses/LeftJoinClause.cs 2011-04-15 18:42:11 UTC (rev 5706) +++ trunk/nhibernate/src/NHibernate/Linq/Clauses/LeftJoinClause.cs 2011-04-15 23:55:13 UTC (rev 5707) @@ -1,12 +0,0 @@ -using System.Linq.Expressions; -using Remotion.Linq.Clauses; - -namespace NHibernate.Linq.Visitors -{ - public class LeftJoinClause : AdditionalFromClause - { - public LeftJoinClause(string itemName, System.Type itemType, Expression fromExpression) : base(itemName, itemType, fromExpression) - { - } - } -} \ No newline at end of file Deleted: trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddLeftJoinsReWriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddLeftJoinsReWriter.cs 2011-04-15 18:42:11 UTC (rev 5706) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddLeftJoinsReWriter.cs 2011-04-15 23:55:13 UTC (rev 5707) @@ -1,95 +0,0 @@ -using System.Collections.Generic; -using System.Linq.Expressions; -using NHibernate.Linq.Visitors; -using Remotion.Linq; -using Remotion.Linq.Clauses; - -namespace NHibernate.Linq.ReWriters -{ - public class AddLeftJoinsReWriter : QueryModelVisitorBase - { - private readonly ISessionFactory _sessionFactory; - - private AddLeftJoinsReWriter(ISessionFactory sessionFactory) - { - _sessionFactory = sessionFactory; - } - - public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory) - { - var rewriter = new AddLeftJoinsReWriter(sessionFactory); - - rewriter.VisitQueryModel(queryModel); - } - - public override void VisitSelectClause(SelectClause selectClause, QueryModel queryModel) - { - selectClause.Selector = JoinReplacer(queryModel, selectClause.Selector); - } - - public override void VisitOrderByClause(OrderByClause orderByClause, QueryModel queryModel, int index) - { - foreach (Ordering ordering in orderByClause.Orderings) - { - ordering.Expression = JoinReplacer(queryModel, ordering.Expression); - } - } - - private Expression JoinReplacer(QueryModel queryModel, Expression expression) - { - var joins = LeftJoinDetector.Detect(expression, new NameGenerator(queryModel), _sessionFactory); - - Expression result = expression; - - if (joins.Joins.Count > 0) - { - result = joins.Selector; - - queryModel.TransformExpressions(e => ExpressionSwapper.Swap(e, joins.ExpressionMap)); - - foreach (var join in joins.Joins) - { - queryModel.BodyClauses.Add(join); - } - } - - return result; - } - } - - public class ExpressionSwapper : NhExpressionTreeVisitor - { - private readonly Dictionary<Expression, Expression> _expressionMap; - - private ExpressionSwapper(Dictionary<Expression, Expression> expressionMap) - { - _expressionMap = expressionMap; - } - - public static Expression Swap(Expression expression, Dictionary<Expression, Expression> expressionMap) - { - var swapper = new ExpressionSwapper(expressionMap); - - return swapper.VisitExpression(expression); - } - - public override Expression VisitExpression(Expression expression) - { - if (expression == null) - { - return null; - } - - Expression replacement; - - if (_expressionMap.TryGetValue(expression, out replacement)) - { - return replacement; - } - else - { - return base.VisitExpression(expression); - } - } - } -} \ No newline at end of file Deleted: trunk/nhibernate/src/NHibernate/Linq/Visitors/LeftJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/LeftJoinDetector.cs 2011-04-15 18:42:11 UTC (rev 5706) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/LeftJoinDetector.cs 2011-04-15 23:55:13 UTC (rev 5707) @@ -1,75 +0,0 @@ -using System.Collections.Generic; -using System.Linq.Expressions; -using Remotion.Linq.Clauses.Expressions; - -namespace NHibernate.Linq.Visitors -{ - public class LeftJoinDetector : NhExpressionTreeVisitor - { - private readonly NameGenerator _nameGenerator; - private readonly ISessionFactory _sessionFactory; - private readonly Dictionary<string, LeftJoinClause> _joins = new Dictionary<string, LeftJoinClause>(); - private readonly Dictionary<Expression, Expression> _expressionMap = new Dictionary<Expression, Expression>(); - - private LeftJoinDetector(NameGenerator nameGenerator, ISessionFactory sessionFactory) - { - _nameGenerator = nameGenerator; - _sessionFactory = sessionFactory; - } - - public static Results Detect(Expression selector, NameGenerator nameGenerator, ISessionFactory sessionFactory) - { - var detector = new LeftJoinDetector(nameGenerator, sessionFactory); - - var newSelector = detector.VisitExpression(selector); - - return new Results(newSelector, detector._joins.Values, detector._expressionMap); - } - - protected override Expression VisitMemberExpression(MemberExpression expression) - { - if (expression.Type.IsNonPrimitive() && IsEntity(expression.Type)) - { - var newExpr = AddJoin(expression); - if (!_expressionMap.ContainsKey(expression) || !_expressionMap[expression].Equals(newExpr)) // Second clause is sanity check. - _expressionMap.Add(expression, newExpr); - return newExpr; - } - - return base.VisitMemberExpression(expression); - } - - private bool IsEntity(System.Type type) - { - return _sessionFactory.GetClassMetadata(type) != null; - } - - private Expression AddJoin(MemberExpression expression) - { - string key = ExpressionKeyVisitor.Visit(expression, null); - LeftJoinClause join; - - if (!_joins.TryGetValue(key, out join)) - { - join = new LeftJoinClause(_nameGenerator.GetNewName(), expression.Type, expression); - _joins.Add(key, join); - } - - return new QuerySourceReferenceExpression(join); - } - - public class Results - { - public Expression Selector { get; private set; } - public ICollection<LeftJoinClause> Joins { get; private set; } - public Dictionary<Expression, Expression> ExpressionMap { get; private set; } - - public Results(Expression selector, ICollection<LeftJoinClause> joins, Dictionary<Expression, Expression> expressionMap) - { - Selector = selector; - Joins = joins; - ExpressionMap = expressionMap; - } - } - } -} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-15 18:42:11 UTC (rev 5706) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-15 23:55:13 UTC (rev 5707) @@ -8,8 +8,8 @@ { /// <summary> /// The WhereJoinDetector creates the joins for the where clause, including - /// optimizations for inner joins. The algorithms are explained in a text - /// attached to JIRA entry NH-2583. + /// optimizations for inner joins. The algorithms are explained in + /// the accompanying text file. /// </summary> internal class WhereJoinDetector : AbstractJoinDetector { Added: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetectorDesignNotes.txt =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetectorDesignNotes.txt (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetectorDesignNotes.txt 2011-04-15 23:55:13 UTC (rev 5707) @@ -0,0 +1,309 @@ +[Commiter's Notes: As with the code, this design document was contributed by Harald Mueller. + By default in Linq, a member expression such as a.B.C is converted into left outer joins so if we have something like a => (a.B.C == 1 || a.D.E == 2) we don't lose records due to the join where B or D is null. + This document describes how we optimize to inner joins when outer joins are not required, such as in the simple case of a => a.B.C == 1. + There was significant discussion on the developers mailing list regarding this topic. See also NH-2583.] + +Optimization of outer joins to inner joins for (||-4) semantics +=============================================================== + +It is interesting - and for some databases an advantage - to replace outer joins with inner joins if the outer joins are not necessary. "Not necessary" here means that the result must not be different whether using outer joins or inner joins. The question, obviously, is: For which joinable member expressions can we replace an outer join with an inner join without creating wrong results? + +It took me a few hours to find this out. Here is the result. + +A record (object) will be in the result if the evaluation of the condition in 3-value SQL logic will return true; it will not be in the result if the result is either logical-null or false. The difference between outer joining and inner joining is that with the latter, objects are missing from the set on which the condition is checked. Thus, inner joins "emulates" a result that is logical-null or false. And therefore, we can replace an outer join with an inner join only if the resulting condition was not true on the outer join in the first place when there was an "empty outer join" - i.e., the outer join had to add nulls because there was no joinable record. + +By the way, I will in the following call the nulls added by "dangling outer joins" "oj-nulls". They have to be distinguished from the two other sorts of nulls in SQL: +* "value-null" - a NULL in a column of a table +* "logical-null" - a NULL resulting from the evaluation of certain conditions on certain values (in SQL, at least one of these values must be a value-null or oj-null). +In contrast to value-nulls, oj-nulls have the peculiar property that they can exist even for non-nullable columns. + +If we look at the evaluation tree of a condition, we can assign to each node and for each joinable member expression one of the following small sets: + + t definitely makes the node true when the member expression is emptily outer-joined (i.e., joining it creates oj-nulls for all the simple properties) + n definitely makes the node logical-null when emptily outer-joined + f definitely makes the node false when emptily outer-joined + tn maybe makes it true, maybe logical-null when emptily outer-joined + tf maybe makes it true, maybe false when emptily outer-joined + nf maybe makes it logical-null, maybe false when emptily outer-joined + tnf maybe makes it true, maybe logical-null, maybe false when emptily outer-joined + +(An eighth set, the empty one, could only be assigned to a contradiction. We ignore such conditions in most of the following discussion). + +When we know these values at the top condition, we can then safely use inner joins for all member expressions for which the value does not contain t. +The reasoning is as follows: If for some result record, the empty outer join of a joinable member expression has made the top where condition logical-null or false, this record will be dropped from the result set - this is just the definition of how a query handles logical-null and false results. But an inner join cannot "do more harm" - it will also just drop the record from the result. Therefore, we can safely replace outer joins to such joinable member expressions with inner joins. + +In the following, we assemble the rules for computing the member expressions mappings introduced above. After a few examples, we look at the rules, and then more examples. + +(Remark: I use C# notation in the following, with the following semantics: +* Generally, the semantics for condition evaluation is 3-valued SQL semantics with condition results of true, logical-null, or false +* == null has the semantics of "is null" +* != null the semantics of "is not null" +* the final result contains objects where the condition evaluation yields true, but not logical-null or false - this is the standard mapping of 3-valued-semantics to 2-valued-semantics). + +As a first example, the condition + + x.A.B == 4 + +is logical-null when emptily outer-joining x.A, but never true or false. Thus, we have { x.A -> n }. Inner joining x.A (which drops records that are emptily joined) therefore yields the same 2-valued-logic result. + +On the other hand, the condition + + x.A.B == null && x.E == null + +can be made true or false by emptily outer-joining x.A, but never logical-null (resaon: The right side can only be true or false; and the left side also; so the complete condition is either true or false - depending on x.E's value). So, { x.A -> tf }, and therefore we cannot inner join x.A (there is a t in the mapping!). By direct reasoning, we see that inner joining x.A will drop all the non-joinable records, hence inner and outer joining are different for records where x.E is null, and will yield a different 2-valued-logic result. + +Finally, the condition + + x.A.B == null || x.E == null + +is always true when emptily outer-joining x.A, so { x.A -> t }. Hence, the result is always different from inner joining, where the empty join drops such records from the result. + +How can we compute the mapping from member expressions to possible values? First, we note that we can compute this mapping with different "preciseness". For example, one correct way would be to just collect all joinable member expressions into a set M, and then set { mE -> tnf } for all member expressions mE in M. Obviously, this prevents any inner joins. On the other hand, we can in principle quite precisely check condition like the following - the question is whether this is worth the effort: + + x.A.B == null x.A -> ... + !(x.A.B != null) x.A -> ... + (x.A.B ?? 4) == 4 x.A -> ... + !((x.A.B ?? 4) != 4) x.A -> ... + (x.A.B ?? x.E) == 4 x.A -> ... + (x.A.B ?? x.C.D) == 4 x.A -> ..., x.C -> ... + +In the following, I'll first give the rules for the 4 logical operators &&, ||, !, and ?!; then I'll give practical rules (I think) for common simple conditions; finally, I'll look at some more complex simple conditions. + +(a) && operator: + + && t n f tn tf nf tnf - + t t n f tn tf nf tnf tnf + n n f n nf nf nf nf + f f f f f f f + tn tn tnf nf tnf tnf + tf tf nf tnf tnf + nf nf nf nf + tnf tnf tnf + - - + +The single letters are easy: They follow the 3-valued SQL logic. E.g., if emptily joining a member expression will definitely return true for condition A and logical-null for condition B, it will definitely return (true && logical-null) = logical-null for A && B. +For the multiple values, we have to compute the union of the values in the small sets. For example, tn && tf is { t && t, t && f, n && t, n && f } = { t,f,n,f } = tnf. +If the member expression is missing on one side, we must assume any value for that side. After all, the condition on the other side could e.g. be 0 == 0, 0 == null, or 0 == 1. Therefore, the result is the same as if we would get tnf from the other side. See examples (ex.4) and (ex.5) below for some more thoughts on this. +The values below the diagonal are symmetric to the upper ones. + +(b) || operator: + + || t n f tn tf nf tnf - + t t t t t t t t t + n n n tn tn n tn tn + f f tn tf nf tnf tnf + tn tn tn tn tn tn + tf tf tnf tnf tnf + nf nf tnf tnf + tnf tnf tnf + - - + +The resoning is similar to &&. +Again, the values below the diagonal are symmetric to the upper ones. + +(c) ! operator: + + ! t n f tn tf nf tnf + f n t nf tf tn tnf + +The resoning is similar to &&. + +(d) Logical ?: operator: + +A ? B : C is equivalent to A && B || !A && C. From this, one can compute the mappings (I would need a three-dimensional "cube matrix" for their presentation, which is hard in text ... ok, a tree also would work ...). + +Now let us look at simple conditions. The following are *possible* member expression mappings. As said above, one can also assign the values more crudely - e.g., always assign tnf to all member expressions. However, the assignments below are reasonable precise - i.e., they assign the minimal sets for practical values (if I did not make a mistake). + +(e) mE*.P <op> <constant(s)> (where <constant(s)> are not value-nulls) + +mE* here is a symbol for a "nested sequence of member expressions" mE1, mE2, ..., .P is the final property. E.g. in + + a.B.C.D.E == 4 + +the member expressions are mE1=a.B, mE2=a.B.C, and mE3=a.B.C.D; the final property is E. In this case, we get { mE -> n } for all member expressions mE. Reason: Emptily outer joining any member expression will yield oj-null for P; but oj-null <op> <constant> is always logical-null. + +(f) mE*.P [<op>s <constant>s] == me'*.Q [<op>s <constant>s] + +The result depends on the definition of ==: We can either use the Linq definition where null == null is true (which requires an SQL translation of ... = ... OR ... IS NULL AND ... IS NULL); or the SQL definition where null == null is logical-null. + +In the first case, we reason as follows: + + - When one side (e.g. the left one) does empty outer-joining and yields oj-null for P, but the right side has non-oj-null values, the SQL + oj-null = value OR oj-null IS NULL AND value IS NULL + evaluates as logical-null OR true AND false, which is logical-null OR true, which is true. + - When both sides do empty outer-joining, we get + oj-null = oj-null OR oj-null IS NULL AND oj-null IS NULL + which is logical-null OR true AND true, which is true. + +So, empty outer joining will always yield true, and hence we get { mE -> t } for all member expressions mE. + +For the SQL definition of equality, we get the following: + + - When one side (e.g. the left one) does empty outer-joining and yields oj-null for P, but the right side has non-oj-null values, the SQL + oj-null = value + evaluates as logical-null. + - When both sides do empty outer-joining, we get + oj-null = oj-null + which is logical-null. + +So, empty outer joining will always yield logical-null, and hence we get { mE -> n } for all member expressions mE. + +(g) mE*.P [<op>s <constant>s] != me'*.Q [<op>s <constant>s] + +Again, the result depends on the definition of ==: We can either use the Linq definition where null != null is false (which requires an SQL translation of ... <> ... OR ... IS NULL AND ... IS NOT NULL OR ... IS NOT NULL AND ... IS NULL); or the SQL definition where null != null is logical-null. + +In the first case, we reason as follows: + + - When one side (e.g. the left one) does empty outer-joining and yields oj-null for P, but the right side has non-oj-null values, the SQL + oj-null <> value OR oj-null IS NULL AND value IS NOT NULL OR oj-null IS NOT NULL AND value IS NULL + evaluates as logical-null OR true AND true OR false AND false, which is true. + - When both sides do empty outer-joining, we get + oj-null <> oj-null OR oj-null IS NULL AND oj-null IS NOT NULL OR oj-null IS NOT NULL AND oj-null IS NULL + which is logical-null OR false OR false, which is logical-null. + +So, empty outer joining will yield true or logical-null, and hence we get { mE -> tn } for all member expressions mE. + +For the SQL definition of equality, we get the following: + + - When one side (e.g. the left one) does empty outer-joining and yields oj-null for P, but the right side has non-oj-null values, the SQL + oj-null <> value + evaluates as logical-null. + - When both sides do empty outer-joining, we get + oj-null <> oj-null + which is also logical-null. + +So, empty outer joining will always yield logical-null, and hence we get { mE -> n } for all member expressions mE. + +(h) mE*.P != null + +Here is a first attempt: Empty outer joining can only yield false, hence we get { mE -> f } for all member expressions mE. + +There is a small problem with this definition: If P itself is a pointer to a mapped entity, we would *not* record that P is guaranteed to point to a valid object. This hurts in the following query: + + x.A != null && x.A.B != 4 + +According to (e), the right side will create the mapping { x.A -> n }. The left side does not have a joinable member expression (x.A is not joined! it is just evaluated on x's table), so the mapping is { }. According to (a), we get for the whole condition { x.A -> nf }. Actually, we know that the result should be { x.A -> f }: An empty outer join of x.A will yield "false" for the left hand side, and hence the complete condition will then always be false - never logical-null. The error is of course that we ignore the knowledge about x.A being a mapped entity. This does not disturb the inner join possibility here (the result does not contain t), and I cannot think of a case where it would - but it's wrong or at least imprecise nevertheless. +A better definition would be: +* If mE*.P does not reference an entity, then { mE -> f } for all member expressions mE. +* Otherwise, also include { mE*.P -> f } in the result. + +(i) mE*.P == null + +Empty outer joining can only yield true, hence we get { mE -> t } for all member expressions mE. Example (ex.4) below hints at an idea that would make this mapping more precise (with questionable practical value). +As above, we can add { mE*.P -> t } if mE*.P references an entity. + +(j) Other complex simple condition, e.g. (x.A.B ?? x.C.D) <op> <constant(s)> + +Here, I opt for the simple assignment { mE -> tnf } for all member expressions mE. It is probably possible to do better by analyzing coalesce operators (??). + +Now, we should do a few examples. + +(ex.1) a.B.C == 2 + + a.B.C == 2 { a.B -> n } (e) + + In this simple case, we can actually inner join a.B. This is also true for conditions like a.B.C > 2 or a.B.C <= 2. + +(ex.2) Show that the typical "in-to-|| translation" will yield inner joins: + + a.B.C == 1 || a.B.C == 2 + + a.B.C == 1 { a.B -> n } (e) + a.B.C == 2 { a.B -> n } (e) + a.B.C == 1 || a.B.C == 2 { a.B -> n } (b) + + As a.B's mapping does not contain a t, we can inner join it. + +(ex.3) a.B.C == null + + a.B.C == null { a.B -> t } (g) + + Even in this simple case, we cannot inner join a.B! + +(ex.4) a.B == null || a.B.C == 1 + + a.B == null { a.B -> t } (i) + a.B.C == 2 { a.B -> n } (e) + a.B == null || a.B.C == 2 { a.B -> t } (b) + + Also in this case, we cannot inner join a.B. The reason is that emptily outer-joining a.B can make the left hand side true (which it actually does). One could argue that we could derive a sharper bound by somehow looking at the meaning of a.B == null: Actually, we can be sure that this condition can only true when emptily outer-joining a.B, and not "true or logical-null or false" as the formal derivation assumes for a missing joinable member expression. Yet, in this example, we would not get a different final result (and I did not think about cases where the more precise reasoning could yield more inner joins). + +(ex.5) + a.E == null || a.B.C == 1 // a.E is an integer property + + a.E == null { } + a.B.C == 2 { a.B -> n } (e) + a.B == null || a.B.C == 2 { a.B -> tn } (b) + + We could compute the result somewhat more precisely: a.E == null can only be true or false, but not logical-null. In such cases, we could tighten the result by also assigning a set of possible values to each node, independent of empty outer joins. With the knowledge that a.E can only map to tf, we would use this set in the || computation, instead of the general pessimistic tnf. Especially when having contradictions (like false or 0 == 1) or tautologies (like true or 0 == 0) in the tree, this would make the result more precise. An interesting example would be a.B.C != a.B.C with SQL equality semantics: It can return only logical-null or false, which could - if this expression occurs - reduce some results containing t and hence allow inner joins. However, all these examples seem artificial: In usual applications, neither contradictions nor tautologies nor a.B.C != a.B.C will occur often enough in queries to justify the additional complexity in the algorithms. + +(ex.6) + a.B != null && a.B.C == 1 + + a.B != null { a.B -> f } (h) + a.B.C == 1 { a.B -> n } (e) + a.B != null && a.B.C == 1 { a.B -> f } (a) + + Thus, we can inner join a.B here. + +(ex.7) + a.B.C == a.D.E || a.B.C == a.D.E + 1 + + a.B.C == a.D.E { a.B -> n, a.D -> n } (f) + a.B.C == a.D.E + 1 { a.B -> n, a.D -> n } (f) + ...complete condition... { a.B -> n, a.D -> n } (b) + + So we can inner join both a.B and a.D in this case! + +(ex.8) + + a.B.C == 1 || a.D.E == 2 + + a.B.C == 1 { a.B -> n } (e) + a.D.E == 2 { a.D -> n } (e) + ...complete condition... { a.B -> tnf, a.D -> tnf } (b) + + We can*not* inner join a.B and a.D in this case. + +(ex.9) + + a.B.C == 1 && a.D.E == 2 + + a.B.C == 1 { a.B -> n } (e) + a.D.E == 1 { a.D -> n } (e) + ...complete condition... { a.B -> nf, a.D -> nf } (a) + + Just by replacing || with && in the previous example, we can inner join both a.B and a.D. + + +The above rules guarantee that the inner joins yield exactly the same results as full outer joining. This, fortunately, has the consequence that the following *cannot* happen: + + A query with conditon C yields a different result than condition C || F, where F is always false. + +Why did I fear that this could happen? In previous rules I had invented, the *operators* in the condition decided whether a joinable member expression was outer joined or inner joined. Especially, the || and ! operators essentially required outer joining for member expressions used in their sub-conditions. But with such a machinery, it could happen that some member expression + +* is *inner* joined for C alone (if there is no || or !) +* is *outer* joined for C || F (as there is now an || operator). + +But this could give us maybe different results if not done perfectly. Actually, there are examples where F is definitely always false, but we still get different joinings for C and C || F with the rules above. Here are two - a simple and a not so simple one: + +(ex.10) + C is the condition x.A.B == 1. + F is the condition 0 == 1. + +(ex.11) + C is the condition x.A.B == 1. + F is the condition x.C.D * x.C.D < Math.Abs(x.C.D) - 1. + +Elementary mathematics shows that F is always false in (ex.11) (for real numbers). But according to the rules above, we get in both (ex.10) and (ex.11) + + for C alone: { x.A -> n } + + for C || F: + C { x.A -> n } (f) + F { x.C -> tnf } (j) // Actually, { } for (ex.10); which is treated like { x.C -> tnf } for ||. + C || F { x.A -> tn, x.C -> tnf } (b), (b) + +Therefore, we can inner join x.A for C alone, but not for C || F. Still, the arguments above show us that we can "carelessly" replace the inner joins with outer joins and still get the same results! So I sleep well with the rules above (I just have to implement them). + +As a final brain-teaser: What intelligence would NHib.Linq have to have to be able to create an inner join to x.A also for C || F in (ex.10) and (ex.11)? Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-15 18:42:11 UTC (rev 5706) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-15 23:55:13 UTC (rev 5707) @@ -273,7 +273,6 @@ <Compile Include="Linq\ReWriters\ResultOperatorRewriter.cs" /> <Compile Include="Linq\ReWriters\ResultOperatorRewriterResult.cs" /> <Compile Include="Linq\Visitors\AbstractJoinDetector.cs" /> - <Compile Include="Linq\Visitors\ExpressionTreeVisitor.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessAggregateFromSeed.cs" /> <Compile Include="Linq\Visitors\SelectAndOrderByJoinDetector.cs" /> <Compile Include="Linq\Visitors\WhereJoinDetector.cs" /> @@ -1771,6 +1770,7 @@ <None Include="Type\IType.cs.xmldoc" /> </ItemGroup> <ItemGroup> + <Content Include="Linq\Visitors\WhereJoinDetectorDesignNotes.txt" /> <Content Include="NamespaceSummary.xml" /> </ItemGroup> <ItemGroup> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-15 18:42:18
|
Revision: 5706 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5706&view=rev Author: patearl Date: 2011-04-15 18:42:11 +0000 (Fri, 15 Apr 2011) Log Message: ----------- Removed ExpressionTreeVisitor since it exposed members that were visiting query source objects, which are marked as internal at the moment. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByKeySelectorVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionTreeVisitor.cs Deleted: trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionTreeVisitor.cs 2011-04-15 04:10:51 UTC (rev 5705) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/ExpressionTreeVisitor.cs 2011-04-15 18:42:11 UTC (rev 5706) @@ -1,160 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.Linq.Expressions; -using Remotion.Linq.Clauses.Expressions; - -namespace NHibernate.Linq.Visitors -{ - /// <summary> - /// This class is used to expose the members from the base class that get internalized when the other class is ilmerged. - /// We do this instead of exposing the base class directly by name, since we don't want it to be part of our public API. - /// </summary> - public class ExpressionTreeVisitor : Remotion.Linq.Parsing.ExpressionTreeVisitor - { - public override ReadOnlyCollection<T> VisitAndConvert<T>(ReadOnlyCollection<T> expressions, string callerName) - { - return base.VisitAndConvert<T>(expressions, callerName); - } - - public override T VisitAndConvert<T>(T expression, string methodName) - { - return base.VisitAndConvert<T>(expression, methodName); - } - - protected override Expression VisitBinaryExpression(BinaryExpression expression) - { - return base.VisitBinaryExpression(expression); - } - - protected override Expression VisitConditionalExpression(ConditionalExpression expression) - { - return base.VisitConditionalExpression(expression); - } - - protected override Expression VisitConstantExpression(ConstantExpression expression) - { - return base.VisitConstantExpression(expression); - } - - protected override ElementInit VisitElementInit(ElementInit elementInit) - { - return base.VisitElementInit(elementInit); - } - - protected override ReadOnlyCollection<ElementInit> VisitElementInitList(ReadOnlyCollection<ElementInit> expressions) - { - return base.VisitElementInitList(expressions); - } - - public override Expression VisitExpression(Expression expression) - { - return base.VisitExpression(expression); - } - - protected override Expression VisitExtensionExpression(ExtensionExpression expression) - { - return base.VisitExtensionExpression(expression); - } - - protected override Expression VisitInvocationExpression(InvocationExpression expression) - { - return base.VisitInvocationExpression(expression); - } - - protected override Expression VisitLambdaExpression(LambdaExpression expression) - { - return base.VisitLambdaExpression(expression); - } - - protected override Expression VisitListInitExpression(ListInitExpression expression) - { - return base.VisitListInitExpression(expression); - } - - protected override MemberBinding VisitMemberAssignment(MemberAssignment memberAssigment) - { - return base.VisitMemberAssignment(memberAssigment); - } - - protected override MemberBinding VisitMemberBinding(MemberBinding memberBinding) - { - return base.VisitMemberBinding(memberBinding); - } - - protected override ReadOnlyCollection<MemberBinding> VisitMemberBindingList(ReadOnlyCollection<MemberBinding> expressions) - { - return base.VisitMemberBindingList(expressions); - } - - protected override Expression VisitMemberExpression(MemberExpression expression) - { - return base.VisitMemberExpression(expression); - } - - protected override Expression VisitMemberInitExpression(MemberInitExpression expression) - { - return base.VisitMemberInitExpression(expression); - } - - protected override MemberBinding VisitMemberListBinding(MemberListBinding listBinding) - { - return base.VisitMemberListBinding(listBinding); - } - - protected override MemberBinding VisitMemberMemberBinding(MemberMemberBinding binding) - { - return base.VisitMemberMemberBinding(binding); - } - - protected override Expression VisitMethodCallExpression(MethodCallExpression expression) - { - return base.VisitMethodCallExpression(expression); - } - - protected override Expression VisitNewArrayExpression(NewArrayExpression expression) - { - return base.VisitNewArrayExpression(expression); - } - - protected override Expression VisitNewExpression(NewExpression expression) - { - return base.VisitNewExpression(expression); - } - - protected override Expression VisitParameterExpression(ParameterExpression expression) - { - return base.VisitParameterExpression(expression); - } - - protected override Expression VisitQuerySourceReferenceExpression(Remotion.Linq.Clauses.Expressions.QuerySourceReferenceExpression expression) - { - return base.VisitQuerySourceReferenceExpression(expression); - } - - protected override Expression VisitSubQueryExpression(Remotion.Linq.Clauses.Expressions.SubQueryExpression expression) - { - return base.VisitSubQueryExpression(expression); - } - - protected override Expression VisitTypeBinaryExpression(TypeBinaryExpression expression) - { - return base.VisitTypeBinaryExpression(expression); - } - - protected override Expression VisitUnaryExpression(UnaryExpression expression) - { - return base.VisitUnaryExpression(expression); - } - - [Obsolete] - protected override Expression VisitUnknownExpression(Expression expression) - { - return base.VisitUnknownExpression(expression); - } - - protected override Expression VisitUnknownNonExtensionExpression(Expression expression) - { - return base.VisitUnknownNonExtensionExpression(expression); - } - } -} Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByKeySelectorVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByKeySelectorVisitor.cs 2011-04-15 04:10:51 UTC (rev 5705) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/GroupByKeySelectorVisitor.cs 2011-04-15 18:42:11 UTC (rev 5706) @@ -1,5 +1,6 @@ using System.Linq.Expressions; using Remotion.Linq.Clauses.Expressions; +using Remotion.Linq.Parsing; namespace NHibernate.Linq.Visitors { Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs 2011-04-15 04:10:51 UTC (rev 5705) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/NhExpressionTreeVisitor.cs 2011-04-15 18:42:11 UTC (rev 5706) @@ -1,6 +1,7 @@ using System; using System.Linq.Expressions; using NHibernate.Linq.Expressions; +using Remotion.Linq.Parsing; namespace NHibernate.Linq.Visitors { Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs 2011-04-15 04:10:51 UTC (rev 5705) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectClauseVisitor.cs 2011-04-15 18:42:11 UTC (rev 5706) @@ -4,6 +4,7 @@ using NHibernate.Hql.Ast; using NHibernate.Linq.Expressions; using NHibernate.Linq.Functions; +using Remotion.Linq.Parsing; namespace NHibernate.Linq.Visitors { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <pa...@us...> - 2011-04-15 04:10:59
|
Revision: 5705 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5705&view=rev Author: patearl Date: 2011-04-15 04:10:51 +0000 (Fri, 15 Apr 2011) Log Message: ----------- Harald Mueller's great contribution that fixes joins for member expression chains, especially where || operators are involved. This is basically the original patch. (NH-2583) Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/NHibernate.Test.csproj Added Paths: ----------- trunk/nhibernate/src/NHibernate/Linq/Clauses/NhJoinClause.cs trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddJoinsReWriter.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/AbstractJoinDetector.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectAndOrderByJoinDetector.cs trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/Domain.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/Mappings.hbm.xml trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingNotAndDeMorganFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOneOrTreeFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingOrderByFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingSelectFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingThreeOrTreesSideBySideFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/MassTestingTwoOrTreesSideBySideFixture.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/SelfJoinTestFixture.cs Added: trunk/nhibernate/src/NHibernate/Linq/Clauses/NhJoinClause.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Clauses/NhJoinClause.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Clauses/NhJoinClause.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,23 @@ +using System.Linq.Expressions; +using Remotion.Linq.Clauses; +using Remotion.Linq.Clauses; + +namespace NHibernate.Linq.Visitors +{ + /// <summary> + /// All joins are created as outer joins. An optimization in <see cref="WhereJoinDetector"/> finds + /// joins that may be inner joined and calls <see cref="MakeInner"/> on them. + /// <see cref="QueryModelVisitor"/>'s <see cref="QueryModelVisitor.VisitAdditionalFromClause"/> will + /// then emit the correct HQL join. + /// </summary> + public class NhJoinClause : AdditionalFromClause + { + public bool IsInner { get; private set; } + public void MakeInner() { + IsInner = true; + } + public NhJoinClause(string itemName, System.Type itemType, Expression fromExpression) : base(itemName, itemType, fromExpression) { + IsInner = false; + } + } +} Added: trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddJoinsReWriter.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddJoinsReWriter.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/ReWriters/AddJoinsReWriter.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.Visitors; +using Remotion.Linq; +using Remotion.Linq.Clauses; +using Remotion.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.ReWriters +{ + internal interface IIsEntityDecider + { + bool IsEntity(System.Type type); + } + + public class AddJoinsReWriter : QueryModelVisitorBase, IIsEntityDecider + { + private readonly Dictionary<string, NhJoinClause> _joins = new Dictionary<string, NhJoinClause>(); + private readonly Dictionary<MemberExpression, QuerySourceReferenceExpression> _expressionMap = new Dictionary<MemberExpression, QuerySourceReferenceExpression>(); + private readonly NameGenerator _nameGenerator; + private readonly ISessionFactory _sessionFactory; + + private AddJoinsReWriter(NameGenerator nameGenerator, ISessionFactory sessionFactory) + { + _nameGenerator = nameGenerator; + _sessionFactory = sessionFactory; + } + + public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory) + { + new AddJoinsReWriter(new NameGenerator(queryModel), sessionFactory).ReWrite(queryModel); + } + + private void ReWrite(QueryModel queryModel) + { + VisitQueryModel(queryModel); + + if (_joins.Count > 0) + { + MemberExpressionSwapper swap = new MemberExpressionSwapper(_expressionMap); + queryModel.TransformExpressions(swap.VisitExpression); + + foreach (var join in _joins.Values) + { + queryModel.BodyClauses.Add(join); + } + } + } + + public override void VisitSelectClause(SelectClause selectClause, QueryModel queryModel) + { + new SelectAndOrderByJoinDetector(_nameGenerator, this, _joins, _expressionMap).VisitExpression(selectClause.Selector); + } + + public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index) + { + WhereJoinDetector.Find(whereClause.Predicate,_nameGenerator, + this, + _joins, + _expressionMap); + } + + public override void VisitOrderByClause(OrderByClause orderByClause, QueryModel queryModel, int index) + { + var joinDetector = new SelectAndOrderByJoinDetector(_nameGenerator, this, _joins, _expressionMap); + foreach (Ordering ordering in orderByClause.Orderings) + { + joinDetector.VisitExpression(ordering.Expression); + } + } + + public bool IsEntity(System.Type type) + { + return _sessionFactory.GetClassMetadata(type) != null; + } + } + + public class MemberExpressionSwapper : NhExpressionTreeVisitor + { + private readonly Dictionary<MemberExpression, QuerySourceReferenceExpression> _expressionMap; + + public MemberExpressionSwapper(Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) + { + _expressionMap = expressionMap; + } + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + if (expression == null) + { + return null; + } + + QuerySourceReferenceExpression replacement; + + if (_expressionMap.TryGetValue(expression, out replacement)) + { + return replacement; + } + else + { + return base.VisitMemberExpression(expression); + } + } + } +} Added: trunk/nhibernate/src/NHibernate/Linq/Visitors/AbstractJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/AbstractJoinDetector.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/AbstractJoinDetector.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.ReWriters; +using Remotion.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.Visitors +{ + public abstract class AbstractJoinDetector : NhExpressionTreeVisitor + { + private readonly NameGenerator _nameGenerator; + internal readonly IIsEntityDecider _isEntityDecider; + protected readonly Dictionary<string, NhJoinClause> _joins; + protected readonly Dictionary<MemberExpression, QuerySourceReferenceExpression> _expressionMap; + + internal AbstractJoinDetector(NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) + { + _nameGenerator = nameGenerator; + _expressionMap = expressionMap; + _joins = joins; + _isEntityDecider = isEntityDecider; + } + + protected internal Expression AddJoin(MemberExpression expression) + { + string key = ExpressionKeyVisitor.Visit(expression, null); + NhJoinClause join; + + if (!_joins.TryGetValue(key, out join)) + { + join = new NhJoinClause(_nameGenerator.GetNewName(), expression.Type, expression); + _joins.Add(key, join); + } + + QuerySourceReferenceExpression newExpr = new QuerySourceReferenceExpression(join); + + if (!_expressionMap.ContainsKey(expression)) + _expressionMap.Add(expression, newExpr); + + return newExpr; + } + + protected void MakeInnerIfJoined(string memberExpressionKey) + { + // memberExpressionKey is not joined if it occurs only at tails of expressions, e.g. + // a.B == null, a.B != null, a.B == c.D etc. + if (_joins.ContainsKey(memberExpressionKey)) + { + _joins[memberExpressionKey].MakeInner(); + } + } + } +} Modified: trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2011-04-14 21:27:16 UTC (rev 5704) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/QueryModelVisitor.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -41,8 +41,8 @@ // Flatten pointless subqueries QueryReferenceExpressionFlattener.ReWrite(queryModel); - // Add left joins for references - AddLeftJoinsReWriter.ReWrite(queryModel, parameters.SessionFactory); + // Add joins for references + AddJoinsReWriter.ReWrite(queryModel, parameters.SessionFactory); // Move OrderBy clauses to end MoveOrderByToEndRewriter.ReWrite(queryModel); @@ -202,12 +202,20 @@ public override void VisitAdditionalFromClause(AdditionalFromClause fromClause, QueryModel queryModel, int index) { - if (fromClause is LeftJoinClause) + if (fromClause is NhJoinClause) { - // It's a left join - _hqlTree.AddFromClause(_hqlTree.TreeBuilder.LeftJoin( - HqlGeneratorExpressionTreeVisitor.Visit(fromClause.FromExpression, VisitorParameters).AsExpression(), - _hqlTree.TreeBuilder.Alias(fromClause.ItemName))); + if (((NhJoinClause)fromClause).IsInner) + { + _hqlTree.AddFromClause(_hqlTree.TreeBuilder.Join( + HqlGeneratorExpressionTreeVisitor.Visit(fromClause.FromExpression, VisitorParameters).AsExpression(), + _hqlTree.TreeBuilder.Alias(fromClause.ItemName))); + } + else + { + _hqlTree.AddFromClause(_hqlTree.TreeBuilder.LeftJoin( + HqlGeneratorExpressionTreeVisitor.Visit(fromClause.FromExpression, VisitorParameters).AsExpression(), + _hqlTree.TreeBuilder.Alias(fromClause.ItemName))); + } } else if (fromClause.FromExpression is MemberExpression) { Added: trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectAndOrderByJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectAndOrderByJoinDetector.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/SelectAndOrderByJoinDetector.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.ReWriters; +using Remotion.Linq.Clauses.Expressions; + +namespace NHibernate.Linq.Visitors +{ + public class SelectAndOrderByJoinDetector : AbstractJoinDetector + { + internal SelectAndOrderByJoinDetector(NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) + : base(nameGenerator, isEntityDecider, joins, expressionMap) + { + } + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + if (expression.Type.IsNonPrimitive() && _isEntityDecider.IsEntity(expression.Type)) { + return AddJoin(expression); + } + + return base.VisitMemberExpression(expression); + } + } +} Added: trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Linq/Visitors/WhereJoinDetector.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,340 @@ +using System.Collections.Generic; +using System.Linq.Expressions; +using NHibernate.Linq.ReWriters; +using Remotion.Linq.Clauses.Expressions; +using Remotion.Linq.Utilities; + +namespace NHibernate.Linq.Visitors +{ + /// <summary> + /// The WhereJoinDetector creates the joins for the where clause, including + /// optimizations for inner joins. The algorithms are explained in a text + /// attached to JIRA entry NH-2583. + /// </summary> + internal class WhereJoinDetector : AbstractJoinDetector + { + // Possible results of a condition when emptily outer joined. + private const int T = 1; + private const int N = 2; + private const int TN = T | N; + private const int F = 4; + private const int TF = T | F; + private const int NF = N | F; + private const int TNF = T | N | F; + + // Composition rules for possible results when emptily outer joined + // for &&, ||, !. + private static readonly int[,] AND = new int[8, 8]; + private static readonly int[,] OR = new int[8, 8]; + private static readonly int[] NOT = new int[8]; + + /// <summary> + /// Setup of <see cref="AND"/>, <see cref="OR"/>, <see cref="NOT"/>. + /// </summary> + static WhereJoinDetector() + { + // Setup of simple values according to SQL 3-valued logic. + NOT[T] = F; + NOT[N] = N; + NOT[F] = T; + + foreach (var p in new[] { T, N, F }) + { + OR[p, p] = AND[p, p] = p; + AND[p, F] = AND[F, p] = F; + OR[p, T] = OR[T, p] = T; + } + AND[T, N] = AND[N, T] = N; + OR[F, N] = OR[N, F] = N; + + // Setup of compound values. Idea: Split each + // compound value to simple values, compute results + // for simple values and or them together. + var allValues = new[] { T, N, TN, F, TF, NF, TNF }; + + // How compound values are split up into simple values. + var split = new int[8][]; + split[T] = new[] { T }; + split[N] = new[] { N }; + split[TN] = new[] { T, N }; + split[F] = new[] { F }; + split[TF] = new[] { T, F }; + split[NF] = new[] { N, F }; + split[TNF] = new[] { T, N, F }; + + foreach (var p in allValues) + { + int[] splitP = split[p]; + // We only need to compute NOT for compound values. + if (splitP.Length > 1) + { + int notResult = 0; + foreach (var p0 in splitP) + { + notResult |= NOT[p0]; + } + NOT[p] = notResult; + } + foreach (var q in allValues) + { + int[] splitQ = split[q]; + // We must compute AND and OR if both values are compound, + // *but also* if one is compound and the other is simple + // (e.g. T and TNF). + if (splitP.Length > 1 || splitQ.Length > 1) + { + int andResult = 0; + int orResult = 0; + foreach (var p0 in splitP) + { + foreach (var q0 in splitQ) + { + andResult |= AND[p0, q0]; + orResult |= OR[p0, q0]; + } + } + AND[p, q] = andResult; + OR[p, q] = orResult; + } + } + } + } + + // The following is used for all *condition* traversal (but not *expressions* that are not conditions). + // This is the "mapping" described in the text at NH-2583. + private Dictionary<string, int> _memberExpressionMapping = new Dictionary<string, int>(); + + // The following two are used for member expressions traversal. + private HashSet<string> _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + private int _memberExpressionDepth = 0; + + internal + WhereJoinDetector(NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) + : base(nameGenerator, isEntityDecider, joins, expressionMap) + { + } + + protected override Expression VisitBinaryExpression(BinaryExpression expression) + { + ArgumentUtility.CheckNotNull("expression", expression); + + Expression baseResult = expression; + if (expression.NodeType == ExpressionType.AndAlso && expression.Type == typeof(bool)) + { + // Case (a) from the text at NH-2583. + var newLeft = VisitExpression(expression.Left); + + var leftMapping = _memberExpressionMapping; + + var newRight = VisitExpression(expression.Right); + + var rightMapping = _memberExpressionMapping; + + _memberExpressionMapping = BinaryMapping(leftMapping, rightMapping, AND); + + // The following is copy-pasted from Relinq's visitor, as I had to split the code above. + var newConversion = (LambdaExpression)VisitExpression(expression.Conversion); + if (newLeft != expression.Left || newRight != expression.Right || newConversion != expression.Conversion) + baseResult = Expression.MakeBinary(expression.NodeType, newLeft, newRight, expression.IsLiftedToNull, expression.Method, newConversion); + } + else if (expression.NodeType == ExpressionType.OrElse && expression.Type == typeof(bool)) + { + // Case (b) + var newLeft = VisitExpression(expression.Left); + + var leftMapping = _memberExpressionMapping; + + var newRight = VisitExpression(expression.Right); + + var rightMapping = _memberExpressionMapping; + + _memberExpressionMapping = BinaryMapping(leftMapping, rightMapping, OR); + + // Again, the following is copy-pasted from Relinq's visitor, as I had to split the code above. + var newConversion = (LambdaExpression)VisitExpression(expression.Conversion); + if (newLeft != expression.Left || newRight != expression.Right || newConversion != expression.Conversion) + baseResult = Expression.MakeBinary(expression.NodeType, newLeft, newRight, expression.IsLiftedToNull, expression.Method, newConversion); + } + else if (expression.Type == typeof(bool) + && (expression.NodeType == ExpressionType.Equal && !IsNullConstantExpression(expression.Right) && !IsNullConstantExpression(expression.Left) + || expression.NodeType == ExpressionType.NotEqual && !IsNullConstantExpression(expression.Right) && !IsNullConstantExpression(expression.Left) + || expression.NodeType == ExpressionType.LessThan + || expression.NodeType == ExpressionType.LessThanOrEqual + || expression.NodeType == ExpressionType.GreaterThan + || expression.NodeType == ExpressionType.GreaterThanOrEqual)) + { + // Cases (e), (f).2, (g).2 + _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + + baseResult = base.VisitBinaryExpression(expression); + + _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, N); + } + else if (expression.Type == typeof(bool) + && expression.NodeType == ExpressionType.NotEqual) + { + // Case (h) + _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + + baseResult = base.VisitBinaryExpression(expression); + + _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, F); + } + else if (expression.Type == typeof(bool) + && expression.NodeType == ExpressionType.Equal) + { + // Case (i) + _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + + baseResult = base.VisitBinaryExpression(expression); + + _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, T); + } + else // +, * etc. + { + // Case (j) + _collectedPathMemberExpressionsInExpression = new HashSet<string>(); + + baseResult = base.VisitBinaryExpression(expression); + + _memberExpressionMapping = FixedMapping(_collectedPathMemberExpressionsInExpression, TNF); + } + return baseResult; + } + + private static Dictionary<string, int> FixedMapping(IEnumerable<string> collectedPathMemberExpressionsInExpression, int value) + { + var memberExpressionMapping = new Dictionary<string, int>(); + foreach (var me in collectedPathMemberExpressionsInExpression) + { + memberExpressionMapping.Add(me, value); + } + return memberExpressionMapping; + } + + private static Dictionary<string, int> BinaryMapping(Dictionary<string, int> leftMapping, Dictionary<string, int> rightMapping, int[,] op) + { + var result = new Dictionary<string, int>(); + // Compute mapping for all member expressions in leftMapping. If the member expression is missing + // in rightMapping, use TNF as a "pessimistic approximation" instead (inside the ?: operator). See + // the text for an explanation of this. + foreach (var lhs in leftMapping) + { + result.Add(lhs.Key, op[lhs.Value, rightMapping.ContainsKey(lhs.Key) ? rightMapping[lhs.Key] : TNF]); + } + // Compute mapping for all member expressions *only* in rightMapping (we did the common ones above). + // Again, use TNF as pessimistic approximation to result of left subcondition. + foreach (var rhs in rightMapping) + { + if (!leftMapping.ContainsKey(rhs.Key)) + { + result[rhs.Key] = op[rhs.Value, TNF]; + } + } + return result; + } + + private static bool IsNullConstantExpression(Expression expression) + { + if (expression is ConstantExpression) + { + var constant = (ConstantExpression)expression; + return constant.Value == null; + } + else + { + return false; + } + } + + protected override Expression VisitUnaryExpression(UnaryExpression expression) + { + ArgumentUtility.CheckNotNull("expression", expression); + + Expression baseResult; + if (expression.NodeType == ExpressionType.Not && expression.Type == typeof(bool)) + { + // Case (c) from text at NH-2583. + baseResult = VisitExpression(expression.Operand); + + var opMapping = _memberExpressionMapping; + _memberExpressionMapping = new Dictionary<string, int>(); + + foreach (var m in opMapping) + { + _memberExpressionMapping.Add(m.Key, NOT[m.Value]); + } + } + else + { + baseResult = base.VisitUnaryExpression(expression); + } + return baseResult; + } + + //protected override Expression VisitConditionalExpression(ConditionalExpression expression) + //{ + // ArgumentUtility.CheckNotNull("expression", expression); + + // VisitExpression(expression.Test); + // // If the ?: returns bool, it is (most probably ...) a condition which may require outer joins. + // // TODO: Check check whether HQL accepts ?: conditions; if not, should be rewritten it as (a && b || !a && c). + // if (expression.Type == typeof(bool)) + // { + // ... + // } + // return expression; + //} + + protected override Expression VisitMemberExpression(MemberExpression expression) + { + ArgumentUtility.CheckNotNull("expression", expression); + + Expression newExpression; + try + { + _memberExpressionDepth++; + newExpression = base.VisitExpression(expression.Expression); + } + finally + { + _memberExpressionDepth--; + } + bool isEntity = _isEntityDecider.IsEntity(expression.Type); + + if (isEntity) + { + // See (h) why we do not check for _memberExpressionDepth here! + _collectedPathMemberExpressionsInExpression.Add(ExpressionKeyVisitor.Visit(expression, null)); + } + + if (_memberExpressionDepth > 0 && isEntity) + { + return AddJoin(expression); + } + else + { + if (newExpression != expression.Expression) + return Expression.MakeMemberAccess(newExpression, expression.Member); + return expression; + } + } + + internal static void Find(Expression expression, NameGenerator nameGenerator, IIsEntityDecider isEntityDecider, Dictionary<string, NhJoinClause> joins, Dictionary<MemberExpression, QuerySourceReferenceExpression> expressionMap) + { + WhereJoinDetector f = new WhereJoinDetector(nameGenerator, isEntityDecider, joins, expressionMap); + + f.VisitExpression(expression); + + foreach (var mapping in f._memberExpressionMapping) + { + // If outer join can never produce true, we can safely inner join. + if ((mapping.Value & T) == 0) + { + f.MakeInnerIfJoined(mapping.Key); + } + } + } + + } +} Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-14 21:27:16 UTC (rev 5704) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2011-04-15 04:10:51 UTC (rev 5705) @@ -266,12 +266,17 @@ <Compile Include="ISessionFactory.cs" /> <Compile Include="ITransaction.cs" /> <Compile Include="LazyInitializationException.cs" /> + <Compile Include="Linq\Clauses\NhJoinClause.cs" /> <Compile Include="Linq\Functions\DictionaryGenerator.cs" /> + <Compile Include="Linq\ReWriters\AddJoinsReWriter.cs" /> <Compile Include="Linq\ReWriters\MoveOrderByToEndRewriter.cs" /> <Compile Include="Linq\ReWriters\ResultOperatorRewriter.cs" /> <Compile Include="Linq\ReWriters\ResultOperatorRewriterResult.cs" /> + <Compile Include="Linq\Visitors\AbstractJoinDetector.cs" /> <Compile Include="Linq\Visitors\ExpressionTreeVisitor.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessAggregateFromSeed.cs" /> + <Compile Include="Linq\Visitors\SelectAndOrderByJoinDetector.cs" /> + <Compile Include="Linq\Visitors\WhereJoinDetector.cs" /> <Compile Include="Loader\Loader.cs" /> <Compile Include="Loader\OuterJoinLoader.cs" /> <Compile Include="LockMode.cs" /> @@ -892,7 +897,6 @@ <Compile Include="Linq\Expressions\NhMinExpression.cs" /> <Compile Include="Linq\Expressions\NhSumExpression.cs" /> <Compile Include="Impl\ExpressionQueryImpl.cs" /> - <Compile Include="Linq\ReWriters\AddLeftJoinsReWriter.cs" /> <Compile Include="Linq\Visitors\IHqlExpressionVisitor.cs" /> <Compile Include="Linq\GroupJoin\IsAggregatingResults.cs" /> <Compile Include="Linq\GroupJoin\GroupJoinAggregateDetectionVisitor.cs" /> @@ -908,7 +912,6 @@ <Compile Include="Linq\Functions\StringGenerator.cs" /> <Compile Include="Linq\Functions\QueryableGenerator.cs" /> <Compile Include="Linq\ReWriters\RemoveUnnecessaryBodyOperators.cs" /> - <Compile Include="Linq\Clauses\LeftJoinClause.cs" /> <Compile Include="Linq\IntermediateHqlTree.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessCast.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessOfType.cs" /> @@ -922,7 +925,6 @@ <Compile Include="Linq\Visitors\ResultOperatorProcessors\ResultOperatorProcessorBase.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessResultOperatorReturn.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\IResultOperatorProcessor.cs" /> - <Compile Include="Linq\Visitors\LeftJoinDetector.cs" /> <Compile Include="Linq\Visitors\NameGenerator.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessAggregate.cs" /> <Compile Include="Linq\Visitors\ResultOperatorProcessors\ProcessAll.cs" /> Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,254 @@ +using NHibernate.Linq; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace NHibernate.Test.NHSpecificTest.NH2583 +{ + public abstract class AbstractMassTestingFixture : BugTestCase + { + private class ValueTuple<T1, T2, T3, T4, T5, T6, T7> + { + public T1 Item1; + public T2 Item2; + public T3 Item3; + public T4 Item4; + public T5 Item5; + public T6 Item6; + public T7 Item7; + } + + private static IEnumerable<ValueTuple<T1, T2, T3, T4, T5, T6, T7>> GetAllTestCases<T1, T2, T3, T4, T5, T6, T7>() + { + foreach (T1 v1 in Enum.GetValues(typeof(T1))) + { + foreach (T2 v2 in Enum.GetValues(typeof(T2))) + { + foreach (T3 v3 in Enum.GetValues(typeof(T3))) + { + foreach (T4 v4 in Enum.GetValues(typeof(T4))) + { + foreach (T5 v5 in Enum.GetValues(typeof(T5))) + { + foreach (T6 v6 in Enum.GetValues(typeof(T6))) + { + foreach (T7 v7 in Enum.GetValues(typeof(T7))) + { + yield return + new ValueTuple<T1, T2, T3, T4, T5, T6, T7> { Item1 = v1, Item2 = v2, Item3 = v3, Item4 = v4, Item5 = v5, Item6 = v6, Item7 = v7 }; + } + } + } + } + } + } + } + } + + public class SetterTuple<T1, T2, T3, T4, T5, T6, T7> + { + private readonly Action<MyBO, ISession, T1> _set1; + private readonly Action<MyBO, ISession, T2> _set2; + private readonly Action<MyBO, ISession, T3> _set3; + private readonly Action<MyBO, ISession, T4> _set4; + private readonly Action<MyBO, ISession, T5> _set5; + private readonly Action<MyBO, ISession, T6> _set6; + private readonly Action<MyBO, ISession, T7> _set7; + + public SetterTuple(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3, + Action<MyBO, ISession, T4> set4, + Action<MyBO, ISession, T5> set5, + Action<MyBO, ISession, T6> set6, + Action<MyBO, ISession, T7> set7) + { + _set1 = set1; + _set2 = set2; + _set3 = set3; + _set4 = set4; + _set5 = set5; + _set6 = set6; + _set7 = set7; + } + + public void Set(MyBO bo, ISession s, T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7) + { + if (_set1 != null) { _set1(bo, s, item1); } + if (_set2 != null) { _set2(bo, s, item2); } + if (_set3 != null) { _set3(bo, s, item3); } + if (_set4 != null) { _set4(bo, s, item4); } + if (_set5 != null) { _set5(bo, s, item5); } + if (_set6 != null) { _set6(bo, s, item6); } + if (_set7 != null) { _set7(bo, s, item7); } + } + } + + + protected void RunTest<T1, T2, T3, T4, T5, T6, T7>(Expression<Func<MyBO, bool>> condition, SetterTuple<T1, T2, T3, T4, T5, T6, T7> setters) + { + if (condition == null) + { + throw new ArgumentNullException("condition"); + } + if (setters == null) + { + throw new ArgumentNullException("setters"); + } + IEnumerable<int> expectedIds; + + // Setup + using (var session = OpenSession()) + { + using (session.BeginTransaction()) + { + using (var tx = session.BeginTransaction()) + { + expectedIds = CreateObjects(session, setters, condition.Compile()); + tx.Commit(); + } + } + } + + try + { + // Test + using (var session = OpenSession()) + { + using (session.BeginTransaction()) + { + TestAndAssert(condition, session, expectedIds); + } + } + + } + finally + { + // Teardown + using (var session = OpenSession()) + { + using (var tx = session.BeginTransaction()) + { + DeleteAll<MyBO>(session); + DeleteAll<MyRef1>(session); + DeleteAll<MyRef2>(session); + DeleteAll<MyRef3>(session); + tx.Commit(); + } + } + } + } + + protected abstract void TestAndAssert(Expression<Func<MyBO, bool>> condition, ISession session, IEnumerable<int> expectedIds); + + protected static SetterTuple<T1, T2, T3, T4, T5, T6, T7> Setters<T1, T2, T3, T4, T5, T6, T7>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3, + Action<MyBO, ISession, T4> set4, + Action<MyBO, ISession, T5> set5, + Action<MyBO, ISession, T6> set6, + Action<MyBO, ISession, T7> set7) + { + return new SetterTuple<T1, T2, T3, T4, T5, T6, T7>(set1, set2, set3, set4, set5, set6, set7); + } + + protected static SetterTuple<T1, T2, T3, T4, T5, T6, Ignore> Setters<T1, T2, T3, T4, T5, T6>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3, + Action<MyBO, ISession, T4> set4, + Action<MyBO, ISession, T5> set5, + Action<MyBO, ISession, T6> set6) + { + return new SetterTuple<T1, T2, T3, T4, T5, T6, Ignore>(set1, set2, set3, set4, set5, set6, null); + } + + protected static SetterTuple<T1, T2, T3, T4, T5, Ignore, Ignore> Setters<T1, T2, T3, T4, T5>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3, + Action<MyBO, ISession, T4> set4, + Action<MyBO, ISession, T5> set5) + { + return new SetterTuple<T1, T2, T3, T4, T5, Ignore, Ignore>(set1, set2, set3, set4, set5, null, null); + } + + protected static SetterTuple<T1, T2, T3, T4, Ignore, Ignore, Ignore> Setters<T1, T2, T3, T4>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3, + Action<MyBO, ISession, T4> set4) + { + return new SetterTuple<T1, T2, T3, T4, Ignore, Ignore, Ignore>(set1, set2, set3, set4, null, null, null); + } + + protected static SetterTuple<T1, T2, T3, Ignore, Ignore, Ignore, Ignore> Setters<T1, T2, T3>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2, + Action<MyBO, ISession, T3> set3) + { + return new SetterTuple<T1, T2, T3, Ignore, Ignore, Ignore, Ignore>(set1, set2, set3,null, null, null, null); + } + + protected static SetterTuple<T1, T2, Ignore, Ignore, Ignore, Ignore, Ignore> Setters<T1, T2>(Action<MyBO, ISession, T1> set1, + Action<MyBO, ISession, T2> set2) + { + return new SetterTuple<T1, T2, Ignore, Ignore, Ignore, Ignore, Ignore>(set1, set2, null, null, null, null, null); + } + + protected static SetterTuple<T1, Ignore, Ignore, Ignore, Ignore, Ignore, Ignore> Setters<T1>(Action<MyBO, ISession, T1> set1) + { + return new SetterTuple<T1, Ignore, Ignore, Ignore, Ignore, Ignore, Ignore>(set1, null, null, null, null, null, null); + } + + private static void DeleteAll<T>(ISession session) + { + foreach (var bo in session.Query<T>()) + { + session.Delete(bo); + } + } + + private static IEnumerable<int> CreateObjects<T1, T2, T3, T4, T5, T6, T7>(ISession session, SetterTuple<T1, T2, T3, T4, T5, T6, T7> setters, Func<MyBO, bool> condition) + { + var expectedIds = new List<int>(); + bool thereAreSomeWithTrue = false; + bool thereAreSomeWithFalse = false; + foreach (var q in GetAllTestCases<T1, T2, T3, T4, T5, T6, T7>()) + { + MyBO bo = new MyBO(); + setters.Set(bo, session, q.Item1, q.Item2, q.Item3, q.Item4, q.Item5, q.Item6, q.Item7); + try + { + if (condition(bo)) + { + expectedIds.Add(bo.Id); + thereAreSomeWithTrue = true; + } + else + { + thereAreSomeWithFalse = true; + } + session.Save(bo); + } + catch (NullReferenceException) + { + // ignore - we only check consistency with Linq2Objects in non-failing cases; + // emulating the outer-join logic for exceptional cases in Lin2Objects is IMO very hard. + } + } + if (!thereAreSomeWithTrue) + { + throw new ArgumentException("Condition is false for all - not a good test", "condition"); + } + if (!thereAreSomeWithFalse) + { + throw new ArgumentException("Condition is true for all - not a good test", "condition"); + } + return expectedIds; + } + + protected static void AreEqual(IEnumerable<int> expectedIds, IEnumerable<int> actualList) + { + Assert.That(() => actualList.ToList(), Is.EquivalentTo(expectedIds)); + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/Domain.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/Domain.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/Domain.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,261 @@ +namespace NHibernate.Test.NHSpecificTest.NH2583 +{ + public class MyRef1 + { + private static int _idCt = 1000; + private int _id; + + public MyRef1() + { + _id = ++_idCt; + } + + public virtual int Id { + get { return _id; } + set { _id = value; } + } + + public virtual int? I1 { get; set; } + public virtual int I2 { get; set; } + public virtual int I3 { get; set; } + + public virtual MyRef2 BO2 { get; set; } + public virtual MyRef3 BO3 { get; set; } + + public virtual MyRef2 GetOrCreateBO2(ISession s) + { + if (BO2 == null) + { + BO2 = new MyRef2(); + s.Save(BO2); + } + return BO2; + } + + public virtual MyRef3 GetOrCreateBO3(ISession s) + { + if (BO3 == null) + { + BO3 = new MyRef3(); + s.Save(BO3); + } + return BO3; + } + } + + public class MyRef2 + { + private static int _idCt = 1000; + private int _id; + + public MyRef2() + { + _id = ++_idCt; + } + + public virtual int Id { + get { return _id; } + set { _id = value; } + } + + public virtual int? J1 { get; set; } + public virtual int J2 { get; set; } + public virtual int J3 { get; set; } + } + + public class MyRef3 + { + private static int _idCt = 3000; + private int _id; + + public MyRef3() + { + _id = ++_idCt; + } + + public virtual int Id { + get { return _id; } + set { _id = value; } + } + + public virtual int L1 { get; set; } + } + + public enum Ignore { Ignore } + public enum TK { Zero, One } + public enum TBO1_I { Null, Zero, One } + public enum TBO2_J { Null, Zero, One } + public enum TBO1_BO2_J { Null, BO1, Zero, One } + public enum TBO1_BO3_L { Null, BO1, Zero, One } + + public class MyBO + { + private static int _idCt = 0; + private int _id; + + public MyBO() + { + _id = ++_idCt; + } + + public virtual int Id { + get { return _id; } + set { _id = value; } + } + + public virtual string Name { get; set; } + public virtual MyBO LeftSon { get; set; } + public virtual MyBO RightSon { get; set; } + public virtual MyRef1 BO1 { get; set; } + public virtual MyRef1 OtherBO1 { get; set; } + public virtual MyRef2 BO2 { get; set; } + public virtual int? K1 { get; set; } + public virtual int K2 { get; set; } + public virtual int K3 { get; set; } + + private MyRef1 GetOrCreateBO1(ISession s) + { + if (BO1 == null) + { + BO1 = new MyRef1(); + s.Save(BO1); + } + return BO1; + } + + private MyRef2 GetOrCreateBO2(ISession s) + { + if (BO2 == null) + { + BO2 = new MyRef2(); + s.Save(BO2); + } + return BO2; + } + + public static void SetK1(MyBO bo, ISession s, TK value) + { + bo.K1 = value == TK.One ? 1 : 0; + } + + public static void SetK2(MyBO bo, ISession s, TK value) + { + bo.K2 = value == TK.One ? 1 : 0; + } + + public static void SetK3(MyBO bo, ISession s, TK value) + { + bo.K3 = value == TK.One ? 1 : 0; + } + + private static void SetBO1_I(MyBO bo, ISession s, TBO1_I value, System.Action<MyRef1, int> set) + { + switch (value) + { + case TBO1_I.Null: + bo.BO1 = null; + break; + case TBO1_I.One: + set(bo.GetOrCreateBO1(s), 1); + break; + case TBO1_I.Zero: + set(bo.GetOrCreateBO1(s), 0); + break; + } + } + + public static void SetBO1_I1(MyBO bo, ISession s, TBO1_I value) + { + SetBO1_I(bo, s, value, (b, i) => b.I1 = i); + } + + public static void SetBO1_I2(MyBO bo, ISession s, TBO1_I value) + { + SetBO1_I(bo, s, value, (b, i) => b.I2 = i); + } + + public static void SetBO1_I3(MyBO bo, ISession s, TBO1_I value) + { + SetBO1_I(bo, s, value, (b, i) => b.I3 = i); + } + + private static void SetBO2_J(MyBO bo, ISession s, TBO2_J value, System.Action<MyRef2, int> set) + { + switch (value) + { + case TBO2_J.Null: + bo.BO2 = null; + break; + case TBO2_J.One: + set(bo.GetOrCreateBO2(s), 1); + break; + case TBO2_J.Zero: + set(bo.GetOrCreateBO2(s), 0); + break; + } + } + + public static void SetBO2_J1(MyBO bo, ISession s, TBO2_J value) + { + SetBO2_J(bo, s, value, (b, i) => b.J1 = i); + } + + public static void SetBO2_J2(MyBO bo, ISession s, TBO2_J value) + { + SetBO2_J(bo, s, value, (b, i) => b.J2 = i); + } + + public static void SetBO2_J3(MyBO bo, ISession s, TBO2_J value) + { + SetBO2_J(bo, s, value, (b, i) => b.J3 = i); + } + + private static void SetBO1_BO2_J(MyBO bo, ISession s, TBO1_BO2_J value, System.Action<MyRef2, int> set) + { + switch (value) + { + case TBO1_BO2_J.Null: + bo.BO1 = null; + break; + case TBO1_BO2_J.BO1: + bo.GetOrCreateBO1(s).BO2 = null; + break; + case TBO1_BO2_J.Zero: + set(bo.GetOrCreateBO1(s).GetOrCreateBO2(s), 0); + break; + case TBO1_BO2_J.One: + set(bo.GetOrCreateBO1(s).GetOrCreateBO2(s), 1); + break; + } + } + + public static void SetBO1_BO2_J1(MyBO bo, ISession s, TBO1_BO2_J value) + { + SetBO1_BO2_J(bo, s, value, (b, i) => b.J1 = i); + } + + public static void Set_BO1_BO2_J2(MyBO bo, ISession s, TBO1_BO2_J value) + { + SetBO1_BO2_J(bo, s, value, (b, i) => b.J2 = i); + } + + public static void SetBO1_BO3_L1(MyBO bo, ISession s, TBO1_BO3_L value) + { + switch (value) + { + case TBO1_BO3_L.Null: + bo.BO1 = null; + break; + case TBO1_BO3_L.BO1: + bo.GetOrCreateBO1(s).BO3 = null; + break; + case TBO1_BO3_L.Zero: + bo.GetOrCreateBO1(s).GetOrCreateBO3(s).L1 = 0; + break; + case TBO1_BO3_L.One: + bo.GetOrCreateBO1(s).GetOrCreateBO3(s).L1 = 1; + break; + } + } + } +} Added: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs (rev 0) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/NH2583/ManualTestFixture.cs 2011-04-15 04:10:51 UTC (rev 5705) @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH2583 +{ + public class ManualTestFixture : BugTestCase + { + /// <summary> + /// This setup is used in most tests in here - but not all; and we might want to + /// twist it for special tests. Therefore, the OnSetUp mechanism is not used. + /// </summary> + [Test] + private void StandardSetUp() + { + using (var session = OpenSession()) + { + using (var tx = session.BeginTransaction()) + { + var i1001 = new MyRef1 { Id = 1001, I1 = null, I2 = 101 }; + var i1101 = new MyRef1 { Id = 1101, I1 = null, I2 = 111 }; + var i1002 = new MyRef1 { Id = 1002, I1 = 12, I2 = 102 }; + var i1003 = new MyRef1 { Id = 1003, I1 = 13, I2 = 103 }; + session.Save(i1001); + session.Save(i1101); + session.Save(i1002); + session.Save(i1003); + + var j2001 = new MyRef2 { Id = 2001, J1 = null, J2 = 201 }; + var j2002 = new MyRef2 { Id = 2002, J1 = 22, J2 = 202 }; + var j2003 = new MyRef2 { Id = 2003, J1 = null, J2 = 203 }; + session.Save(j2001); + session.Save(j2002); + session.Save(j2003); + + var b10 = new MyBO { Id = 10, Name = "1:1001,o1:NULL,2:NULL", BO1 = i1001, OtherBO1 = null, BO2 = null }; + var b11 = new MyBO { Id = 11, Name = "1:1001,o1:1101,2:NULL", BO1 = i1001, OtherBO1 = i1101, BO2 = null }; + var b20 = new MyBO { Id = 20, Name = "1:1002,o1:NULL,2:2002", BO1 = i1002, OtherBO1 = null, BO2 = j2002 }; + var b30 = new MyBO { Id = 30, Name = "1:NULL,o1:NULL,2:2003", BO1 = null, OtherBO1 = null, BO2 = j2003 }; + session.Save(b10); + session.Save(b11); + session.Save(b20); + session.Save(b30); + tx.Commit(); + } + } + } + + public void OrWithTrueShouldBeEqualToTrue() + { + StandardSetUp(); + + int compareCt; + using (var session = OpenSession()) + { + var result = session.Query<MyBO>(); + // 3.1.0/2011-03-19: OK - select mybo0_.Id as Id0_, mybo0_.Name as Name0_, mybo0_.BO1Key as BO3_0_, mybo0_.OtherBO1Key as OtherBO4_0_, mybo0_.BO2Key as BO5_0_ from MyBO mybo0_ + var resultList = result.ToList(); + compareCt = resultList.Count; + Assert.IsTrue(compareCt > 0); + } + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => true); + // 3.1.0/2011-03-19: OK - exec sp_executesql N'select mybo0_.Id as Id0_, mybo0_.Name as Name0_, mybo0_.BO1Key as BO3_0_, mybo0_.OtherBO1Key as OtherBO4_0_, mybo0_.BO2Key as BO5_0_ from MyBO mybo0_ where @p0=1',N'@p0 bit',@p0=1 + var resultList = result.ToList(); + Assert.AreEqual(compareCt, resultList.Count); + } + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => + bo.BO1 != null && bo.BO1.I2 == 101 + || true + ); + // 3.1.0/2011-03-19: WRONG - exec sp_executesql N'select mybo0_.Id as Id0_, mybo0_.Name as Name0_, mybo0_.BO1Key as BO3_0_, mybo0_.OtherBO1Key as OtherBO4_0_, mybo0_.BO2Key as BO5_0_ from MyBO mybo0_, MyRef1 myref1x1_ where mybo0_.BO1Key=myref1x1_.Id and ((mybo0_.BO1Key is not null) and myref1x1_.I2=@p0 or @p1=1)',N'@p0 int,@p1 bit',@p0=101,@p1=1 + var resultList = result.ToList(); + Assert.AreEqual(compareCt, resultList.Count); + } + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => + bo.BO1 != null && bo.BO1.I2 == 101 + || bo.Id == bo.Id + 0 + ); + // 3.1.0/2011-03-19: WRONG - exec sp_executesql N'select mybo0_.Id as Id0_, mybo0_.Name as Name0_, mybo0_.BO1Key as BO3_0_, mybo0_.OtherBO1Key as OtherBO4_0_, mybo0_.BO2Key as BO5_0_ from MyBO mybo0_, MyRef1 myref1x1_ where mybo0_.BO1Key=myref1x1_.Id and ((mybo0_.BO1Key is not null) and myref1x1_.I2=@p0 or mybo0_.Id=mybo0_.Id+@p1)',N'@p0 int,@p1 int',@p0=101,@p1=0 + var resultList = result.ToList(); + Assert.AreEqual(compareCt, resultList.Count); + } + } + + [Test] + public void OrAndNavigationsShouldUseOuterJoins() + { + StandardSetUp(); + + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => + bo.BO1 != null && bo.BO1.I2 == 101 + // || bo.BO2 != null && bo.BO2.J2 == 203 - is added below! + ); + var resultList = result.ToList(); + Assert.IsTrue(resultList.Count > 0); + } + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => + bo.BO1 != null && bo.BO1.I2 == 101 + || bo.BO2 != null && bo.BO2.J2 == 203 + ); + var resultList = result.ToList(); + Assert.IsTrue(resultList.Count > 0); + } + using (var session = OpenSession()) + { + var result = session.Query<MyBO>() + .Where(bo => + bo.BO1.I2 == 101 && bo.BO1 != null + || bo.BO2.J2 == 203 && bo.BO2 != null + ); + var resultList = result.ToList(); + Assert.IsTrue(resultList.Count > 0); + } + } + + [Test] + public void OrShouldBeCompatibleWithAdditionForNullReferences() + { + // This tests against the "outer join anomaly" of (||-3) semantics. + StandardSetUp(); + + using (var session = OpenSession()) + { + List<MyBO> leftResult; + List<MyBO> rightResult; + List<MyBO> orResult; + TestCoreOrShouldBeCompatibleWithSum(session, + bo => bo.BO1.I2 == null, + bo => bo.BO2.J2 == null, + bo => bo.BO1.I2 == null || bo.BO2.J2 == null, out leftResult, out rightResult, out orResult); + //Assert.AreEqual(0, leftResult.Count); + //Assert.AreEqual(0, rightResult.Count); + //Assert.AreEqual(0, orResult.Count); + + } + } + + private static void TestCoreOrShouldBeCompatibleWithSum(ISession session, + Expression<Func<MyBO, bool>> left, + Expression<Func<MyBO, bool>> right, + Expression<Func<MyBO, bool>> both, + out List<MyBO> leftResult, + out List<MyBO> rightResult, + out List<MyBO> orResult) + { + leftResult = session.Query<MyBO>() + .Where(left + ).ToList(); + + rightResult = session.Query<MyBO>() + .Where(right + ).ToList(); + + orResult = session.Query<MyBO>() + .Where(both + ).ToList(); + Assert.IsTrue(orResult.Count <= leftResult.Count + rightResult.Count); + } + + [Test] + public void OrShouldBeCompatibleWithAdditionForNonNullReferences() + { + // This tests one case of existing references - so that we do not fall + // into trap of testing only empty results that might be empty for other reasons. + StandardSetUp(); + + using (var session = OpenSession()) + { + List<MyBO> leftResult; + List<MyBO> rightResult; + List<MyBO> orResult; + TestCoreOrShouldBeCompatibleWithSum(session, + bo => bo.BO1.I1 == null, + bo => bo.BO2.J1 == null, + bo => bo.BO1.I1 == null || bo.BO2.J1 == null, out leftResult, out rightResult, out orResult); + Assert.That(() => leftResult.Count, Is.GreaterThan(0)); + Assert.That(() => rightResult.Count, Is.GreaterThan(0)); + Assert.That(() => orResult.Count, Is.GreaterThan(0)); + } + } + + [Test, Ignore("Pure Outer Join semantics has projection anomaly!")] + public void ProjectionDoesNotChangeResult() + { + // This tests against the "projection anomaly" of (||-4) semantics. + using (var session = OpenSession()) + { + using (var tx = session.BeginTransaction()) + { + var i1001 = new MyRef1 { Id = 1001, I1 = null, I2 = 101 }; + var i1101 = new MyRef1 { Id = 1101, I1 = null, I2 = 111 }; + session.Save(i1001); + session.Save(i1101); + + var b1 = new MyBO { Id = 1, Name = "1:1001", BO1 = i1001 }; + var b2 = new MyBO { Id = 2, Name = "2:1101", BO1 = i1101 }; + var b3 = new MyBO { Id = 3, Name = "3:1101", BO1 = i1101 }; + var b4 = new MyBO { Id = 4, Name = "4:NULL", BO1 = null }; + session.Save(b1); + session.Save(b2); + session.Save(b3); + session.Save(b4); + tx.Commit(); + }... [truncated message content] |
From: <pa...@us...> - 2011-04-14 21:27:22
|
Revision: 5704 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5704&view=rev Author: patearl Date: 2011-04-14 21:27:16 +0000 (Thu, 14 Apr 2011) Log Message: ----------- Improved build menu for grammar generation. Modified Paths: -------------- trunk/nhibernate/ShowBuildMenu.bat Modified: trunk/nhibernate/ShowBuildMenu.bat =================================================================== --- trunk/nhibernate/ShowBuildMenu.bat 2011-04-14 19:50:38 UTC (rev 5703) +++ trunk/nhibernate/ShowBuildMenu.bat 2011-04-14 21:27:16 UTC (rev 5704) @@ -117,64 +117,74 @@ :grammar echo. echo --- GRAMMAR --- -echo A. Regenerate HqlLexer.cs and HqlParser.cs from Hql.g. -echo B. Regenerate HqlSqlWalker.cs from HqlSqlWalker.g. -echo C. Regenerate SqlGenerator.cs from SqlGenerator.g. -echo D. Regenerate Hql.g in debug mode. -echo E. Regenerate HqlSqlWalker.g in debug mode. -echo F. Regenerate SqlGenerator.g in debug mode. -echo G. Quick instructions on using debug mode. +echo A. Regenerate all grammars. +echo Hql.g to HqlLexer.cs +echo Hql.g to HqlParser.cs +echo HqlSqlWalker.g to HqlSqlWalker.cs +echo SqlGenerator.g to SqlGenerator.cs +echo B. Regenerate all grammars, with Hql.g in debug mode. +echo C. Regenerate all grammars, with HqlSqlWalker.g in debug mode. +echo D. Regenerate all grammars, with SqlGenerator.g in debug mode. +echo E. Quick instructions on using debug mode. echo. if exist %SYSTEMROOT%\System32\choice.exe ( goto grammar-prompt-choice ) goto grammar-prompt-set :grammar-prompt-choice -choice /C:abcdefg +choice /C:abcde if errorlevel 255 goto end -if errorlevel 7 goto antlr-debug -if errorlevel 6 goto antlr-sqlgenerator-debug -if errorlevel 5 goto antlr-hqlsqlwalker-debug -if errorlevel 4 goto antlr-hql-debug -if errorlevel 3 goto antlr-sqlgenerator -if errorlevel 2 goto antlr-hqlsqlwalker -if errorlevel 1 goto antlr-hql +if errorlevel 5 goto antlr-debug +if errorlevel 4 goto antlr-sqlgenerator-debug +if errorlevel 3 goto antlr-hqlsqlwalker-debug +if errorlevel 2 goto antlr-hql-debug +if errorlevel 1 goto antlr-all if errorlevel 0 goto end :grammar-prompt-set -set /p OPT=[A, B, C, D, E, F, G]? +set /p OPT=[A, B, C, D, E]? -if /I "%OPT%"=="A" goto antlr-hql -if /I "%OPT%"=="B" goto antlr-hqlsqlwalker -if /I "%OPT%"=="C" goto antlr-sqlgenerator -if /I "%OPT%"=="D" goto antlr-hql-debug -if /I "%OPT%"=="E" goto antlr-hqlsqlwalker-debug -if /I "%OPT%"=="F" goto antlr-sqlgenerator -if /I "%OPT%"=="G" goto antlr-debug +if /I "%OPT%"=="A" goto antlr-all +if /I "%OPT%"=="B" goto antlr-hql-debug +if /I "%OPT%"=="C" goto antlr-hqlsqlwalker-debug +if /I "%OPT%"=="D" goto antlr-sqlgenerator-debug +if /I "%OPT%"=="E" goto antlr-debug goto grammar-prompt-set -:antlr-hql +:antlr-all +echo *** Regenerating from Hql.g call src\NHibernate\Hql\Ast\ANTLR\AntlrHql.bat -goto end - -:antlr-hqlsqlwalker +echo *** Regenerating from HqlSqlWalker.g call src\NHibernate\Hql\Ast\ANTLR\AntlrHqlSqlWalker.bat -goto end - -:antlr-sqlgenerator +echo *** Regenerating from SqlGenerator.g call src\NHibernate\Hql\Ast\ANTLR\AntlrSqlGenerator.bat goto end :antlr-hql-debug +echo *** Regenerating from Hql.g (Debug Enabled) call src\NHibernate\Hql\Ast\ANTLR\AntlrHqlDebug.bat +echo *** Regenerating from HqlSqlWalker.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrHqlSqlWalker.bat +echo *** Regenerating from SqlGenerator.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrSqlGenerator.bat goto end :antlr-hqlsqlwalker-debug +echo *** Regenerating from Hql.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrHql.bat +echo *** Regenerating from HqlSqlWalker.g (Debug Enabled) call src\NHibernate\Hql\Ast\ANTLR\AntlrHqlSqlWalkerDebug.bat +echo *** Regenerating from SqlGenerator.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrSqlGenerator.bat goto end :antlr-sqlgenerator-debug +echo *** Regenerating from Hql.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrHql.bat +echo *** Regenerating from HqlSqlWalker.g +call src\NHibernate\Hql\Ast\ANTLR\AntlrHqlSqlWalker.bat +echo *** Regenerating from SqlGenerator.g (Debug Enabled) call src\NHibernate\Hql\Ast\ANTLR\AntlrSqlGeneratorDebug.bat goto end @@ -184,8 +194,9 @@ echo The one you want to debug must be the first grammar parsed. echo 2. Run the unit test. It will appear to stall. echo 3. Download and run AntlrWorks (java -jar AntlrWorks.jar). -echo 4. Choose "Debug Remote" and accept the default port. -echo 5. You should now be connected and able to step through your grammar. +echo 4. Open the grammar you intend to debug in AntlrWorks. +echo 5. Choose "Debug Remote" and accept the default port. +echo 6. You should now be connected and able to step through your grammar. goto end :teamcity-menu This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |