diff --git a/src/FluentNHibernate.Testing/Cfg/MappingConfigurationTests.cs b/src/FluentNHibernate.Testing/Cfg/MappingConfigurationTests.cs index 6a337d448..608a3c752 100644 --- a/src/FluentNHibernate.Testing/Cfg/MappingConfigurationTests.cs +++ b/src/FluentNHibernate.Testing/Cfg/MappingConfigurationTests.cs @@ -4,6 +4,7 @@ using FluentNHibernate.Cfg; using FluentNHibernate.Conventions.Helpers; using FluentNHibernate.Diagnostics; +using FluentNHibernate.MappingModel.Output; using FluentNHibernate.Testing.DomainModel; using FluentNHibernate.Testing.Fixtures; using NHibernate.Cfg; @@ -180,5 +181,31 @@ public void MergeOutputShouldSetFlagOnFluentPersistenceModelsOnApply() model.MergeMappings.ShouldBeTrue(); } + + [Test] + public void MappingApplicationStrategyShouldPropagateToPersistenceModelIfSet() + { + var model = new PersistenceModel(); + var strategy = new ValidatingHbmMappingApplicationStrategy(); + + mapping.UsePersistenceModel(model); + mapping.UseMappingApplicationStrategy(strategy); + mapping.Apply(new Configuration()); + + model.MappingApplicationStrategy.ShouldBeTheSameAs(strategy); + } + + [Test] + public void MappingApplicationStrategyShouldNotPropagateToPersistenceModelIfEmpty() + { + var model = new PersistenceModel(); + var origStrategy = model.MappingApplicationStrategy; + + mapping.UsePersistenceModel(model); + mapping.UseMappingApplicationStrategy(null); + mapping.Apply(new Configuration()); + + model.MappingApplicationStrategy.ShouldBeTheSameAs(origStrategy); + } } } \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/Hbm/HbmConverterTestHelper.cs b/src/FluentNHibernate.Testing/Hbm/HbmConverterTestHelper.cs new file mode 100644 index 000000000..b592de160 --- /dev/null +++ b/src/FluentNHibernate.Testing/Hbm/HbmConverterTestHelper.cs @@ -0,0 +1,661 @@ +using System; +using System.Collections.Generic; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.Hbm +{ + public class HbmConverterTestHelper + { + /// + /// Variant of + /// which supports custom construction of both FMain and FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the array which stores the translated subobjects + /// is used to construct a new instance of FMain + /// is used to construct a new instance of FSub + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsLooselyTypedArray(Func newFMain, + Func newFSub, Action addFSubToFMain, Func getHSubSuperFromHMain) + where HSub : HSubSuper, new() + { + // Set up a fake converter that registers any HSub instances it generates and returns in a list + var generatedHSubs = new List(); + var fakeConverter = A.Fake>(); + A.CallTo(() => fakeConverter.Convert(A.Ignored)).ReturnsLazily(fSub => + { + var hSub = new HSub(); + generatedHSubs.Add(hSub); + return hSub; + }); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and FMain == FSub + HMain == HSub (e.g., subclasses-of-subclasses) we + // get the real converter for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + IHbmConverter converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate a new fluent main object instance, and add a subobject instance to it + var fMain = newFMain(); + addFSubToFMain(fMain, newFSub()); + + // Now try to convert it + var convertedHMain = converter.Convert(fMain); + + // Finally, check that the array on the converted HMain instance which we expect to contain our converted HSub + // instances actually does, and that the converter was called the correct number of times + getHSubSuperFromHMain(convertedHMain).ShouldEqual(generatedHSubs.ToArray()); + A.CallTo(() => fakeConverter.Convert(A.Ignored)).MustHaveHappened(Repeated.Exactly.Once); + } + + /// + /// Variant of + /// which supports custom construction of FMain. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the array which stores the translated subobjects + /// is used to construct a new instance of FMain + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsLooselyTypedArray(Func newFMain, Action addFSubToFMain, + Func getHSubSuperFromHMain) + where FSub : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectsAsLooselyTypedArray(newFMain, () => new FSub(), + addFSubToFMain, getHSubSuperFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the array which stores the translated subobjects + /// is used to construct a new instance of FSub + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsLooselyTypedArray(Func newFSub, Action addFSubToFMain, + Func getHSubSuperFromHMain) + where FMain : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectsAsLooselyTypedArray(() => new FMain(), newFSub, + addFSubToFMain, getHSubSuperFromHMain); + } + + /// + /// Test that a converter correctly handles the translation of a group of subobjects as an array which is broadly typed and can hold those subobjects. + /// + /// + /// + /// If the array of translated subobjects is narrowly typed for the subobjects (that is, the type stored in the array is + /// exactly the subobject type, not an ancestor of it) then the + /// + /// method should be used in preference to this one. + /// + /// + /// + /// + /// converts from to . The following test checks that the + /// class subobjects are converted to correctly: + /// + /// + /// ShouldConvertSubobjectsAsLooselyTypedArray<HibernateMapping, ImportMapping, HbmMapping, HbmImport, object>( + /// (hibernateMapping, importMapping) => hibernateMapping.AddImport(importMapping), + /// hbmMapping => hbmMapping.import + /// ); + /// + /// + /// Specifically, because the conversion target is typed as object[] rather than HbmClass[] (in this case because the mapping XML specification + /// allows other entries to be included), this method must be used rather than + /// . + /// + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the array which stores the translated subobjects + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsLooselyTypedArray(Action addFSubToFMain, + Func getHSubSuperFromHMain) + where FMain : new() + where FSub : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectsAsLooselyTypedArray(() => new FSub(), addFSubToFMain, getHSubSuperFromHMain); + } + + /// + /// Test that a converter correctly handles the translation of a group of subobjects as an array which is narrowly typed to hold those subobjects. + /// + /// + /// + /// If the array of translated subobjects is broadly typed for the subobjects (that is, the type stored in the array is + /// an ancestor of the subobject type, rather than an exact match) then the + /// + /// method must be used, rather than this one. + /// + /// + /// + /// + /// converts from to . The following test checks that the + /// import subobjects are converted to correctly: + /// + /// + /// ShouldConvertSubobjectsAsStrictlyTypedArray<HibernateMapping, ImportMapping, HbmMapping, HbmImport>( + /// (hibernateMapping, importMapping) => hibernateMapping.AddImport(importMapping), + /// hbmMapping => hbmMapping.import + /// ); + /// + /// + /// Specifically, because the conversion target is typed as HbmImport[] rather than some broader type (for example, object[]), this method should + /// be used in preference to . + /// + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsStrictlyTypedArray(Action addFSubToFMain, Func getHSubFromHMain) + where FMain : new() + where FSub : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectsAsLooselyTypedArray(addFSubToFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FMain. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FMain + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsStrictlyTypedArray(Func newFMain, + Action addFSubToFMain, Func getHSubFromHMain) + where FSub : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectsAsLooselyTypedArray(newFMain, addFSubToFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FSub + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsStrictlyTypedArray(Func newFSub, + Action addFSubToFMain, Func getHSubFromHMain) + where FMain : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectsAsLooselyTypedArray(newFSub, addFSubToFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of both FMain and FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FMain + /// is used to construct a new instance of FSub + /// A handler which will add a fluent subobject to a fluent main object + /// A handler which will retrieve an array of translated subobjects from the translated main object + public static void ShouldConvertSubobjectsAsStrictlyTypedArray(Func newFMain, Func newFSub, + Action addFSubToFMain, Func getHSubFromHMain) + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectsAsLooselyTypedArray(newFMain, newFSub, addFSubToFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of both FMain and FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the field which stores the translated subobject + /// is used to construct a new instance of FMain + /// is used to construct a new instance of FSub + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsLooselyTypedField(Func newFMain, Func newFSub, + Action setFSubOnFMain, Func getHSubSuperFromHMain) + where HSub : HSubSuper, new() + { + // Set up a fake converter that registers any HSub instances it generates and returns in a list + var generatedHSubs = new List(); + var fakeConverter = A.Fake>(); + A.CallTo(() => fakeConverter.Convert(A.Ignored)).ReturnsLazily(fSub => + { + var hSub = new HSub(); + generatedHSubs.Add(hSub); + return hSub; + }); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and FMain == FSub + HMain == HSub (e.g., subclasses-of-subclasses) we + // get the real converter for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + IHbmConverter converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate a new fluent main object instance, and add a subobject instance to it + var fMain = newFMain(); + setFSubOnFMain(fMain, newFSub()); + + // Now try to convert it + var convertedHMain = converter.Convert(fMain); + + // Finally, check that the array on the converted HMain instance which we expect to contain our converted HSub + // instances actually does, and that the converter was called the correct number of times + A.CallTo(() => fakeConverter.Convert(A.Ignored)).MustHaveHappened(Repeated.Exactly.Once); // Do this first since it guarantees the list should have exactly one item + getHSubSuperFromHMain(convertedHMain).ShouldEqual(generatedHSubs[0]); + } + + /// + /// Variant of + /// which supports custom construction of FMain. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the field which stores the translated subobject + /// is used to construct a new instance of FMain + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsLooselyTypedField(Func newFMain, Action setFSubOnFMain, + Func getHSubSuperFromHMain) + where FSub : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectAsLooselyTypedField(newFMain, () => new FSub(), setFSubOnFMain, getHSubSuperFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the field which stores the translated subobject + /// is used to construct a new instance of FSub + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsLooselyTypedField(Func newFSub, Action setFSubOnFMain, + Func getHSubSuperFromHMain) + where FMain : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectAsLooselyTypedField(() => new FMain(), newFSub, setFSubOnFMain, getHSubSuperFromHMain); + } + + /// + /// Test that a converter correctly handles the translation of a single subobject as a field which is broadly typed and can hold the subobject. + /// + /// + /// + /// If the translated subobject field is narrowly typed for the subobject (that is, the type stored in the field is exactly + /// the subobject type, not an ancestor of it) then the + /// + /// method should be used in preference to this one. + /// + /// + /// + /// + /// converts from to . The following tests + /// checks that the Id or subobjects are converted + /// to correctly: + /// + /// + /// ShouldConvertSubobjectAsLooselyTypedField<ClassMapping, IIdentityMapping, HbmClass, object, object>( + /// () => new IdMapping(), + /// (classMapping, iidMapping) => classMapping.Set(fluent => fluent.Id, Layer.Conventions, iidMapping), + /// hbmClass => hbmClass.Item + /// ); + /// + /// ShouldConvertSubobjectAsLooselyTypedField<ClassMapping, IIdentityMapping, HbmClass, object, object>( + /// () => new CompositeIdMapping(), + /// (classMapping, iidMapping) => classMapping.Set(fluent => fluent.Id, Layer.Conventions, iidMapping), + /// hbmClass => hbmClass.Item + /// ); + /// + /// + /// Specifically, because the conversion target is typed as object rather than HbmCache (in this case because the mapping XML specification + /// allows other entries to be included), this method must be used rather than + /// . + /// + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// the type of the field which stores the translated subobject + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsLooselyTypedField(Action setFSubOnFMain, + Func getHSubSuperFromHMain) + where FMain : new() + where FSub : new() + where HSub : HSubSuper, new() + { + ShouldConvertSubobjectAsLooselyTypedField(() => new FSub(), setFSubOnFMain, getHSubSuperFromHMain); + } + + /// + /// Test that a converter correctly handles the translation of a single subobject as a field which is narrowly typed to hold the subobject. + /// + /// + /// + /// If the translated subobject field is broadly typed for the subobject (that is, the type stored in the field is exactly + /// the subobject type, not an ancestor of it) then the + /// + /// method must be used, rather than this one. + /// + /// + /// + /// + /// converts from to . The following test + /// checks that the cache subobject is converted to correctly: + /// + /// + /// ShouldConvertSubobjectAsStrictlyTypedField<ClassMapping, CacheMapping, HbmClass, HbmCache>( + /// (classMapping, cacheMapping) => classMapping.Set(fluent => fluent.Cache, Layer.Conventions, cacheMapping), + /// hbmClass => hbmClass.cache + /// ); + /// + /// + /// Specifically, because the conversion target is typed as HbmImport rather than some broader type (for example, object), this method should + /// be used in preference to + /// . + /// + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsStrictlyTypedField(Action setFSubOnFMain, Func getHSubFromHMain) + where FMain : new() + where FSub : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectAsLooselyTypedField(setFSubOnFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FMain. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FMain + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsStrictlyTypedField(Func newFMain, Action setFSubOnFMain, + Func getHSubFromHMain) + where FSub : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectAsLooselyTypedField(newFMain, setFSubOnFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FSub + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsStrictlyTypedField(Func newFSub, Action setFSubOnFMain, + Func getHSubFromHMain) + where FMain : new() + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectAsLooselyTypedField(newFSub, setFSubOnFMain, getHSubFromHMain); + } + + /// + /// Variant of + /// which supports custom construction of both FMain and FSub. + /// + /// + /// the fluent type under test + /// the fluent subobject type under test + /// the translated (Hibernate) type + /// the translated (Hibernate) subobject type + /// is used to construct a new instance of FMain + /// is used to construct a new instance of FSub + /// A handler which will set a fluent subobject on a fluent main object + /// A handler which will retrieve a translated subobject from the translated main object + public static void ShouldConvertSubobjectAsStrictlyTypedField(Func newFMain, Func newFSub, + Action setFSubOnFMain, Func getHSubFromHMain) + where HSub : new() + { + // Strictly typed is just loosely typed with HSubSuper == HSub to restrict it to being exactly HSub + ShouldConvertSubobjectAsLooselyTypedField(newFMain, newFSub, setFSubOnFMain, getHSubFromHMain); + } + + /// + /// Test that a converter which handles a fluent type with children correctly converts a particular input type to the expected output type. + /// + /// + /// + /// If the translated object type is determined by an aspect of the mapping object, rather than by inheritance-based logic, + /// then should be used instead of this + /// method. + /// + /// + /// + /// + /// converts from to . The + /// following calls check that the descendants and are converted + /// to and , respectively. + /// + /// + /// ShouldConvertSpecificHbmForMappingChild(); + /// ShouldConvertSpecificHbmForMappingChild(); + /// + /// + /// + /// the shared ancestor type under test + /// the specific fluent type under test + /// the translated (Hibernate) shared ancestor type + /// the translated (Hibernate) target type + public static void ShouldConvertSpecificHbmForMappingChild() + where F : FSuper, new() + where H : HSuper, new() + { + ShouldConvertSpecificHbmForMapping(() => new F()); + } + + /// + /// Test that a converter which handles a fluent type with subtypes correctly converts a particular input subtype to the expected output type. + /// + /// + /// + /// If the translated object type is determined by inheritance-based logic rather than by an aspect of the mapping + /// object itself, then should be used + /// instead of this method. + /// + /// + /// + /// + /// converts from to , based on the + /// value of . The following calls check that the subtypes , , and + /// are converted to , , and , + /// respectively. + /// + /// + /// ShouldConvertSpecificHbmForMappingSubtype( + /// () => new SubclassMapping(SubclassType.Subclass) + /// ); + /// ShouldConvertSpecificHbmForMappingSubtype( + /// () => new SubclassMapping(SubclassType.JoinedSubclass) + /// ); + /// ShouldConvertSpecificHbmForMappingSubtype( + /// () => new SubclassMapping(SubclassType.UnionSubclass) + /// ); + /// + /// + /// + /// the specific fluent type under test + /// the translated (Hibernate) shared ancestor type + /// the translated (Hibernate) target type + /// is used to construct a new instance of F (which is generally expected to select the specific + /// subtype for the test) + public static void ShouldConvertSpecificHbmForMappingSubtype(Func newF) + where H : HSuper, new() + { + /* NOTE: Ideally, this test would register additional converters for all of the other targets and ensure that they + * were not called. However, while it is possible to detect all such converters, C#'s generic model combined with + * the limitations of FakeItEasy do not provide any straightforward way to register fakes for types that would have + * to be dynamically detected at runtime. So at least for now, we don't do that. + */ + + ShouldConvertSpecificHbmForMapping(newF); + } + + /// + /// Test that a converter which handles a fluent type with both children and subtypes correctly converts a particular + /// input child or subtype to the expected output type. + /// + /// + /// + /// This method combines the logic for and + /// . Tests that only need to address one + /// of the two output selection modes should use one of those methods in preference to this one. + /// + /// + /// + /// + /// converts from to , based on the + /// whether the input is an or an , and in the case of + /// whether is specified. The following calls check that all + /// three situations are handled correctly. + /// + /// + /// + /// ShouldConvertSpecificHbmForMapping( + /// () => NewIndexMappingWithNoOffset() + /// ); + /// ShouldConvertSpecificHbmForMapping( + /// () => NewIndexMappingWithOffset() + /// ); + /// ShouldConvertSpecificHbmForMappingChild(); + /// + /// + /// + /// + /// the shared ancestor type under test + /// the specific fluent type under test + /// the translated (Hibernate) shared ancestor type + /// the translated (Hibernate) target type + /// is used to construct a new instance of F (which is generally expected to select the + /// specific subtype for the test, where relevant) + public static void ShouldConvertSpecificHbmForMapping(Func newF) + where F: FSuper + where H : HSuper, new() + { + // Set up a fake converter that registers any H instances it generates and returns in a list + var generatedHbms = new List(); + var fakeConverter = A.Fake>(); + A.CallTo(() => fakeConverter.Convert(A.Ignored)).ReturnsLazily(fSub => + { + var hbm = new H(); + generatedHbms.Add(hbm); + return hbm; + }); + + // Set up a custom container with the fake F->H converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and HSuper == H we get the real converter for the "outer" call but the + // fake for any "inner" calls. + var container = new HbmConverterContainer(); + IHbmConverter converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate an instance of the descendant type, but explicitly label it as the ancestor type to ensure that we pass it correctly + F mapping = newF(); + + // Now try to convert it + var convertedHbm = converter.Convert(mapping); + + // Check that the converter for the specific descendant was invoked the correct number of times and that the returned value is the converted instance. + A.CallTo(() => fakeConverter.Convert(A.Ignored)).MustHaveHappened(Repeated.Exactly.Once); // Do this first since it guarantees the list should have exactly one item + convertedHbm.ShouldEqual(generatedHbms[0]); + } + } +} diff --git a/src/FluentNHibernate.Testing/Mapping/TypeMappingTests.cs.backup b/src/FluentNHibernate.Testing/Mapping/TypeMappingTests.cs.backup new file mode 100644 index 000000000..75a78fe01 --- /dev/null +++ b/src/FluentNHibernate.Testing/Mapping/TypeMappingTests.cs.backup @@ -0,0 +1,21 @@ +using FluentNHibernate.Mapping; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.Mapping +{ + [TestFixture] + public class TypeMappingTests + { + [Test] + public void GetStringTypeDoesNotDuplicateStrings() + { + var typeString1 = TypeMapping.GetTypeString(typeof(TypeMappingTests)); + var typeString2 = TypeMapping.GetTypeString(typeof(TypeMappingTests)); + + // First make sure that the strings are equal, otherwise something has gone _very_ strong + typeString1.ShouldEqual(typeString2); + // Now make sure that they are the same object, not just equal + typeString1.ShouldBeTheSameAs(typeString2); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/ClassMappingTester.cs b/src/FluentNHibernate.Testing/MappingModel/ClassMappingTester.cs index d9229da65..cb86bfa38 100644 --- a/src/FluentNHibernate.Testing/MappingModel/ClassMappingTester.cs +++ b/src/FluentNHibernate.Testing/MappingModel/ClassMappingTester.cs @@ -1,9 +1,11 @@ -using System.Linq; +using System; +using System.Linq; using FluentNHibernate.MappingModel; using FluentNHibernate.MappingModel.ClassBased; using FluentNHibernate.MappingModel.Identity; using FluentNHibernate.Visitors; using FakeItEasy; +using FluentNHibernate.MappingModel.Collections; using NUnit.Framework; namespace FluentNHibernate.Testing.MappingModel @@ -47,6 +49,46 @@ public void CanAddProperty() mapping.Properties.ShouldContain(property); } + [Test] + public void ShouldFailToAddDuplicateProperty() + { + var property1 = new PropertyMapping(); + property1.Set(x => x.Name, Layer.Defaults, "Property1"); + mapping.AddProperty(property1); + + var property2 = new PropertyMapping(); + property2.Set(x => x.Name, Layer.Defaults, property1.Name); + Assert.Throws(() => mapping.AddProperty(property2)); + + mapping.Properties.ShouldContain(property => ReferenceEquals(property, property1)); + mapping.Properties.ShouldNotContain(property => ReferenceEquals(property, property2)); + } + + [Test] + public void CanAddOrReplaceNewProperty() + { + var property1 = new PropertyMapping(); + property1.Set(x => x.Name, Layer.Defaults, "Property1"); + mapping.AddOrReplaceProperty(property1); + + mapping.Properties.ShouldContain(property => ReferenceEquals(property, property1)); + } + + [Test] + public void CanAddOrReplaceExistingProperty() + { + var property1 = new PropertyMapping(); + property1.Set(x => x.Name, Layer.Defaults, "Property1"); + mapping.AddOrReplaceProperty(property1); + + var property2 = new PropertyMapping(); + property2.Set(x => x.Name, Layer.Defaults, property1.Name); + mapping.AddOrReplaceProperty(property2); + + mapping.Properties.ShouldNotContain(property => ReferenceEquals(property, property1)); + mapping.Properties.ShouldContain(property => ReferenceEquals(property, property2)); + } + [Test] public void CanAddReference() { @@ -57,6 +99,46 @@ public void CanAddReference() mapping.References.ShouldContain(reference); } + [Test] + public void ShouldFailToAddDuplicateReference() + { + var reference1 = new ManyToOneMapping(); + reference1.Set(x => x.Name, Layer.Defaults, "parent"); + mapping.AddReference(reference1); + + var reference2 = new ManyToOneMapping(); + reference2.Set(x => x.Name, Layer.Defaults, reference1.Name); + Assert.Throws(() => mapping.AddReference(reference2)); + + mapping.References.ShouldContain(reference => ReferenceEquals(reference, reference1)); + mapping.References.ShouldNotContain(reference => ReferenceEquals(reference, reference2)); + } + + [Test] + public void CanAddOrReplaceNewReference() + { + var reference1 = new ManyToOneMapping(); + reference1.Set(x => x.Name, Layer.Defaults, "Reference1"); + mapping.AddOrReplaceReference(reference1); + + mapping.References.ShouldContain(reference => ReferenceEquals(reference, reference1)); + } + + [Test] + public void CanAddOrReplaceExistingReference() + { + var reference1 = new ManyToOneMapping(); + reference1.Set(x => x.Name, Layer.Defaults, "Reference1"); + mapping.AddOrReplaceReference(reference1); + + var reference2 = new ManyToOneMapping(); + reference2.Set(x => x.Name, Layer.Defaults, reference1.Name); + mapping.AddOrReplaceReference(reference2); + + mapping.References.ShouldNotContain(reference => ReferenceEquals(reference, reference1)); + mapping.References.ShouldContain(reference => ReferenceEquals(reference, reference2)); + } + [Test] public void Should_pass_id_to_the_visitor() { @@ -86,11 +168,12 @@ public void Should_not_pass_null_id_to_the_visitor() } [Test] - public void Can_add_subclass() + public void CanAddSubclass() { - var joinedSubclass = new SubclassMapping(SubclassType.JoinedSubclass); - mapping.AddSubclass(joinedSubclass); - mapping.Subclasses.ShouldContain(joinedSubclass); + var subclass = new SubclassMapping(SubclassType.JoinedSubclass); + mapping.AddSubclass(subclass); + + mapping.Subclasses.ShouldContain(subclass); } [Test] @@ -113,13 +196,37 @@ public void Should_pass_subclasses_to_the_visitor() } [Test] - public void Can_add_stored_procedure() + public void CanAddStoredProcedure() { var storedProcedure = new StoredProcedureMapping(); mapping.AddStoredProcedure(storedProcedure); + mapping.StoredProcedures.ShouldContain(storedProcedure); } + [Test] + public void CanAddDuplicateStoredProcedure() + { + // Unlike other types, stored procedures do allow duplicate entries. However, in order to distinguish + // whether two entries are identical or not, we need to set some non-identity attribute on them to be + // a different value. For this test, "Query" is easy enough. + var storedProcedure1 = new StoredProcedureMapping(); + storedProcedure1.Set(x => x.Name, Layer.Defaults, "storedProcedure1"); + storedProcedure1.Set(x => x.Query, Layer.Defaults, "x=y"); + mapping.AddStoredProcedure(storedProcedure1); + + var storedProcedure2 = new StoredProcedureMapping(); + storedProcedure1.Set(x => x.Name, Layer.Defaults, storedProcedure1.Name); + storedProcedure1.Set(x => x.Query, Layer.Defaults, "x=y"); + + // Check that adding the duplicate does _not_ throw + mapping.AddStoredProcedure(storedProcedure2); + + // Now check that both are present in stored procedures tracker + mapping.StoredProcedures.ShouldContain(storedProcedure => ReferenceEquals(storedProcedure, storedProcedure1)); + mapping.StoredProcedures.ShouldContain(storedProcedure => ReferenceEquals(storedProcedure, storedProcedure2)); + } + [Test] public void Should_pass_stored_procedure_to_the_visitor() { @@ -147,5 +254,305 @@ public void Should_pass_the_discriminator_to_the_visitor() A.CallTo(() => visitor.Visit(classMap.Discriminator)).MustHaveHappened(); } + + [Test] + public void CanAddCollection() + { + var collection = CollectionMapping.Bag(); + collection.Set(x => x.Name, Layer.Defaults, "Collection1"); + mapping.AddCollection(collection); + + mapping.Collections.ShouldContain(collection); + } + + [Test] + public void ShouldFailToAddDuplicateCollection() + { + var collection1 = CollectionMapping.Bag(); + collection1.Set(x => x.Name, Layer.Defaults, "Collection1"); + mapping.AddCollection(collection1); + + var collection2 = CollectionMapping.Bag(); + collection2.Set(x => x.Name, Layer.Defaults, collection1.Name); + Assert.Throws(() => mapping.AddCollection(collection2)); + + mapping.Collections.ShouldContain(collection => ReferenceEquals(collection, collection1)); + mapping.Collections.ShouldNotContain(collection => ReferenceEquals(collection, collection2)); + } + + [Test] + public void CanAddOrReplaceNewCollection() + { + var collection1 = CollectionMapping.Bag(); + collection1.Set(x => x.Name, Layer.Defaults, "Collection1"); + mapping.AddOrReplaceCollection(collection1); + + mapping.Collections.ShouldContain(collection => ReferenceEquals(collection, collection1)); + } + + [Test] + public void CanAddOrReplaceExistingCollection() + { + var collection1 = CollectionMapping.Bag(); + collection1.Set(x => x.Name, Layer.Defaults, "Collection1"); + mapping.AddOrReplaceCollection(collection1); + + var collection2 = CollectionMapping.Bag(); + collection2.Set(x => x.Name, Layer.Defaults, collection1.Name); + mapping.AddOrReplaceCollection(collection2); + + mapping.Collections.ShouldNotContain(collection => ReferenceEquals(collection, collection1)); + mapping.Collections.ShouldContain(collection => ReferenceEquals(collection, collection2)); + } + + [Test] + public void CanAddComponent() + { + var component = new ComponentMapping(ComponentType.Component); + component.Set(x => x.Name, Layer.Defaults, "Component1"); + mapping.AddComponent(component); + + mapping.Components.ShouldContain(component); + } + + [Test] + public void ShouldFailToAddDuplicateComponent() + { + var component1 = new ComponentMapping(ComponentType.Component); + component1.Set(x => x.Name, Layer.Defaults, "Component1"); + mapping.AddComponent(component1); + + var component2 = new ComponentMapping(ComponentType.Component); + component2.Set(x => x.Name, Layer.Defaults, component1.Name); + Assert.Throws(() => mapping.AddComponent(component2)); + + mapping.Components.ShouldContain(component => ReferenceEquals(component, component1)); + mapping.Components.ShouldNotContain(component => ReferenceEquals(component, component2)); + } + + [Test] + public void CanAddOrReplaceNewComponent() + { + var component1 = new ComponentMapping(ComponentType.Component); + component1.Set(x => x.Name, Layer.Defaults, "Component1"); + mapping.AddOrReplaceComponent(component1); + + mapping.Components.ShouldContain(component => ReferenceEquals(component, component1)); + } + + [Test] + public void CanAddOrReplaceExistingComponent() + { + var component1 = new ComponentMapping(ComponentType.Component); + component1.Set(x => x.Name, Layer.Defaults, "Component1"); + mapping.AddOrReplaceComponent(component1); + + var component2 = new ComponentMapping(ComponentType.Component); + component2.Set(x => x.Name, Layer.Defaults, component1.Name); + mapping.AddOrReplaceComponent(component2); + + mapping.Components.ShouldNotContain(component => ReferenceEquals(component, component1)); + mapping.Components.ShouldContain(component => ReferenceEquals(component, component2)); + } + + [Test] + public void CanAddOneToOne() + { + var oneToOne = new OneToOneMapping(); + oneToOne.Set(x => x.Name, Layer.Defaults, "OneToOne1"); + mapping.AddOneToOne(oneToOne); + + mapping.OneToOnes.ShouldContain(oneToOne); + } + + [Test] + public void ShouldFailToAddDuplicateOneToOne() + { + var oneToOne1 = new OneToOneMapping(); + oneToOne1.Set(x => x.Name, Layer.Defaults, "OneToOne1"); + mapping.AddOneToOne(oneToOne1); + + var oneToOne2 = new OneToOneMapping(); + oneToOne2.Set(x => x.Name, Layer.Defaults, oneToOne1.Name); + Assert.Throws(() => mapping.AddOneToOne(oneToOne2)); + + mapping.OneToOnes.ShouldContain(oneToOne => ReferenceEquals(oneToOne, oneToOne1)); + mapping.OneToOnes.ShouldNotContain(oneToOne => ReferenceEquals(oneToOne, oneToOne2)); + } + + [Test] + public void CanAddOrReplaceNewOneToOne() + { + var oneToOne1 = new OneToOneMapping(); + oneToOne1.Set(x => x.Name, Layer.Defaults, "OneToOne1"); + mapping.AddOrReplaceOneToOne(oneToOne1); + + mapping.OneToOnes.ShouldContain(oneToOne => ReferenceEquals(oneToOne, oneToOne1)); + } + + [Test] + public void CanAddOrReplaceExistingOneToOne() + { + var oneToOne1 = new OneToOneMapping(); + oneToOne1.Set(x => x.Name, Layer.Defaults, "OneToOne1"); + mapping.AddOrReplaceOneToOne(oneToOne1); + + var oneToOne2 = new OneToOneMapping(); + oneToOne2.Set(x => x.Name, Layer.Defaults, oneToOne1.Name); + mapping.AddOrReplaceOneToOne(oneToOne2); + + mapping.OneToOnes.ShouldNotContain(oneToOne => ReferenceEquals(oneToOne, oneToOne1)); + mapping.OneToOnes.ShouldContain(oneToOne => ReferenceEquals(oneToOne, oneToOne2)); + } + + [Test] + public void CanAddAny() + { + var any = new AnyMapping(); + any.Set(x => x.Name, Layer.Defaults, "Any1"); + mapping.AddAny(any); + + mapping.Anys.ShouldContain(any); + } + + [Test] + public void ShouldFailToAddDuplicateAny() + { + var any1 = new AnyMapping(); + any1.Set(x => x.Name, Layer.Defaults, "Any1"); + mapping.AddAny(any1); + + var any2 = new AnyMapping(); + any2.Set(x => x.Name, Layer.Defaults, any1.Name); + Assert.Throws(() => mapping.AddAny(any2)); + + mapping.Anys.ShouldContain(any => ReferenceEquals(any, any1)); + mapping.Anys.ShouldNotContain(any => ReferenceEquals(any, any2)); + } + + [Test] + public void CanAddOrReplaceNewAny() + { + var any1 = new AnyMapping(); + any1.Set(x => x.Name, Layer.Defaults, "Any1"); + mapping.AddOrReplaceAny(any1); + + mapping.Anys.ShouldContain(any => ReferenceEquals(any, any1)); + } + + [Test] + public void CanAddOrReplaceExistingAny() + { + var any1 = new AnyMapping(); + any1.Set(x => x.Name, Layer.Defaults, "Any1"); + mapping.AddOrReplaceAny(any1); + + var any2 = new AnyMapping(); + any2.Set(x => x.Name, Layer.Defaults, any1.Name); + mapping.AddOrReplaceAny(any2); + + mapping.Anys.ShouldNotContain(any => ReferenceEquals(any, any1)); + mapping.Anys.ShouldContain(any => ReferenceEquals(any, any2)); + } + + [Test] + public void CanAddJoin() + { + var join = new JoinMapping(); + join.Set(x => x.TableName, Layer.Defaults, "TableName1"); + mapping.AddJoin(join); + + mapping.Joins.ShouldContain(join); + } + + [Test] + public void ShouldFailToAddDuplicateJoin() + { + var join1 = new JoinMapping(); + join1.Set(x => x.TableName, Layer.Defaults, "TableName1"); + mapping.AddJoin(join1); + + var join2 = new JoinMapping(); + join2.Set(x => x.TableName, Layer.Defaults, join1.TableName); + Assert.Throws(() => mapping.AddJoin(join2)); + + mapping.Joins.ShouldContain(join => ReferenceEquals(join, join1)); + mapping.Joins.ShouldNotContain(join => ReferenceEquals(join, join2)); + } + + [Test] + public void CanAddOrReplaceNewJoin() + { + var join1 = new JoinMapping(); + join1.Set(x => x.TableName, Layer.Defaults, "Join1"); + mapping.AddOrReplaceJoin(join1); + + mapping.Joins.ShouldContain(join => ReferenceEquals(join, join1)); + } + + [Test] + public void CanAddOrReplaceExistingJoin() + { + var join1 = new JoinMapping(); + join1.Set(x => x.TableName, Layer.Defaults, "Join1"); + mapping.AddOrReplaceJoin(join1); + + var join2 = new JoinMapping(); + join2.Set(x => x.TableName, Layer.Defaults, join1.TableName); + mapping.AddOrReplaceJoin(join2); + + mapping.Joins.ShouldNotContain(join => ReferenceEquals(join, join1)); + mapping.Joins.ShouldContain(join => ReferenceEquals(join, join2)); + } + + [Test] + public void CanAddFilter() + { + var filter = new FilterMapping(); + filter.Set(x => x.Name, Layer.Defaults, "Filter1"); + mapping.AddFilter(filter); + + mapping.Filters.ShouldContain(filter); + } + + [Test] + public void ShouldFailToAddDuplicateFilter() + { + var filter1 = new FilterMapping(); + filter1.Set(x => x.Name, Layer.Defaults, "Filter1"); + mapping.AddFilter(filter1); + + var filter2 = new FilterMapping(); + filter2.Set(x => x.Name, Layer.Defaults, filter1.Name); + Assert.Throws(() => mapping.AddFilter(filter2)); + + mapping.Filters.ShouldContain(filter => ReferenceEquals(filter, filter1)); + mapping.Filters.ShouldNotContain(filter => ReferenceEquals(filter, filter2)); + } + + [Test] + public void CanAddOrReplaceNewFilter() + { + var filter1 = new FilterMapping(); + filter1.Set(x => x.Name, Layer.Defaults, "Filter1"); + mapping.AddOrReplaceFilter(filter1); + + mapping.Filters.ShouldContain(filter => ReferenceEquals(filter, filter1)); + } + + [Test] + public void CanAddOrReplaceExistingFilter() + { + var filter1 = new FilterMapping(); + filter1.Set(x => x.Name, Layer.Defaults, "Filter1"); + mapping.AddOrReplaceFilter(filter1); + + var filter2 = new FilterMapping(); + filter2.Set(x => x.Name, Layer.Defaults, filter1.Name); + mapping.AddOrReplaceFilter(filter2); + + mapping.Filters.ShouldNotContain(filter => ReferenceEquals(filter, filter1)); + mapping.Filters.ShouldContain(filter => ReferenceEquals(filter, filter2)); + } } } \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmAnyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmAnyConverterTester.cs new file mode 100644 index 000000000..9e16c08f9 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmAnyConverterTester.cs @@ -0,0 +1,247 @@ +using System.Collections.Generic; +using System.Linq; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmAnyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertIdTypeIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.IdType, Layer.Conventions, "id"); + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.idtype.ShouldEqual(anyMapping.IdType); + } + + [Test] + public void ShouldNotConvertIdTypeIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.idtype.ShouldEqual(blankHbmAny.idtype); + } + + [Test] + public void ShouldConvertMetaTypeIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.MetaType, Layer.Conventions, new TypeReference("meta")); + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.metatype.ShouldEqual(anyMapping.MetaType.ToString()); + } + + [Test] + public void ShouldNotConvertMetaTypeIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.metatype.ShouldEqual(blankHbmAny.metatype); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Name, Layer.Conventions, "nm"); + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.name.ShouldEqual(anyMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.name.ShouldEqual(blankHbmAny.name); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.access.ShouldEqual(anyMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.access.ShouldEqual(blankHbmAny.access); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Insert, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.insert.ShouldEqual(anyMapping.Insert); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.insert.ShouldEqual(blankHbmAny.insert); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Update, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.update.ShouldEqual(anyMapping.Update); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.update.ShouldEqual(blankHbmAny.update); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.cascade.ShouldEqual(anyMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.cascade.ShouldEqual(blankHbmAny.cascade); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.lazy.ShouldEqual(anyMapping.Lazy); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.lazy.ShouldEqual(blankHbmAny.lazy); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var anyMapping = new AnyMapping(); + anyMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.optimisticlock.ShouldEqual(anyMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var anyMapping = new AnyMapping(); + // Don't set anything on the original mapping + var convertedHbmAny = converter.Convert(anyMapping); + var blankHbmAny = new HbmAny(); + convertedHbmAny.optimisticlock.ShouldEqual(blankHbmAny.optimisticlock); + } + + [Test] + public void ShouldConvertTypeColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ColumnMapping("typeColumn"), + (anyMapping, columnMapping) => anyMapping.AddTypeColumn(Layer.Conventions, columnMapping), + hbmAny => hbmAny.column); + } + + [Test] + public void ShouldConvertIdentifierColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ColumnMapping("idColumn"), + (anyMapping, columnMapping) => anyMapping.AddIdentifierColumn(Layer.Conventions, columnMapping), + hbmAny => hbmAny.column); + } + + [Test] + public void ShouldConvertTypeColumnsBeforeIdentifierColumns() + { + // NOTE: Unlike most subobject conversion tests, this test needs to use a real column converter rather than a mock, + // so that the converted columns can be properly identified from their names (in order to determine whether they + // come through in the correct order). While it would be possible to write a fake converter that would do that, it + // wouldn't really be significantly simpler than the real implementation, so it isn't really worth the bother. + // + // NOTE: This test probably really doesn't belong in this location, since the logic involved is actually controlled + // by the visiting order (when visited, the column mapping handler has no idea whether any given column is from the + // identifier column or type column sets). Keeping it here for now largely because it exists on the XML variant and + // we need to be sure that _something_ is testing for it. + + var anyMapping = new AnyMapping(); + + // Set up interleaved ID and type columns and list at least one ID column first, to make it as difficult as possible to get right. + // Note that we don't mis-order the "1"/"2" variants because there is no natural ordering to either type of column, so simply + // preserving the order they were added in is the best option. + anyMapping.AddIdentifierColumn(Layer.Defaults, new ColumnMapping("idColumn1")); + anyMapping.AddTypeColumn(Layer.Defaults, new ColumnMapping("typeColumn1")); + anyMapping.AddIdentifierColumn(Layer.Defaults, new ColumnMapping("idColumn2")); + anyMapping.AddTypeColumn(Layer.Defaults, new ColumnMapping("typeColumn2")); + + var convertedHbmAny = converter.Convert(anyMapping); + convertedHbmAny.column.Select(any => any.name).ToList().ShouldEqual(new List { "typeColumn1", "typeColumn2", "idColumn1", "idColumn2" }); + } + + [Test] + public void ShouldConvertMetaValues() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (anyMapping, metaValueMapping) => anyMapping.AddMetaValue(metaValueMapping), + hbmAny => hbmAny.metavalue); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmArrayConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmArrayConverterTester.cs new file mode 100644 index 000000000..6ef618180 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmArrayConverterTester.cs @@ -0,0 +1,494 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmArrayConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Base collection attribute value field tests + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.access.ShouldEqual(arrayMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.access.ShouldEqual(blankHbmArray.access); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.batchsize.ShouldEqual(arrayMapping.BatchSize); + Assert.That(convertedHbmArray.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.batchsize.ShouldEqual(blankHbmArray.batchsize); + Assert.That(convertedHbmArray.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.cascade.ShouldEqual(arrayMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.cascade.ShouldEqual(blankHbmArray.cascade); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.check.ShouldEqual(arrayMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.check.ShouldEqual(blankHbmArray.check); + } + + [Test] + public void ShouldConvertCollectionTypeIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, new TypeReference("type")); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.collectiontype.ShouldEqual(arrayMapping.CollectionType.ToString()); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfEmpty() + { + var arrayMapping = CollectionMapping.Array(); + // Array an explicitly empty type reference + arrayMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, TypeReference.Empty); + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.collectiontype.ShouldEqual(blankHbmArray.collectiontype); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.collectiontype.ShouldEqual(blankHbmArray.collectiontype); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmCollectionFetchMode.Subselect; // Defaults to Select, so use something else to properly detect that it changes + + var arrayMapping = CollectionMapping.Array(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + arrayMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmArray.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(arrayMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.fetch.ShouldEqual(blankHbmArray.fetch); + Assert.That(convertedHbmArray.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + // HbmArray, unlike HbmList, doesn't support the generic attribute + /* + [Test] + public void ShouldConvertGenericIfPopulated_True() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Generic, Layer.Conventions, true); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.generic.ShouldEqual(arrayMapping.Generic); + Assert.That(convertedHbmArray.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_False() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Generic, Layer.Conventions, false); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.generic.ShouldEqual(arrayMapping.Generic); + Assert.That(convertedHbmArray.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldNotConvertGenericIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.generic.ShouldEqual(blankHbmArray.generic); + Assert.That(convertedHbmArray.genericSpecified.Equals(false), "Generic was marked as specified"); + } + */ + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.inverse.ShouldEqual(arrayMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.inverse.ShouldEqual(blankHbmArray.inverse); + } + + // HbmArray, unlike HbmList, doesn't support the lazy attribute + /* + [Test] + public void ShouldConvertLazyIfPopulated() + { + var hbmLazy = HbmCollectionLazy.False; // Defaults to True, so use something else to properly detect that it changes + + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Lazy, Layer.Conventions, HbmCollectionConverter.FluentHbmLazyBiDict[hbmLazy]); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.lazy.ShouldEqual(hbmLazy); + Assert.That(convertedHbmArray.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + // Since it is enum-based, Lazy cannot contain any invalid values, so no need to test for that here + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.lazy.ShouldEqual(blankHbmArray.lazy); + Assert.That(convertedHbmArray.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + */ + + [Test] + public void ShouldConvertNameIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.name.ShouldEqual(arrayMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.name.ShouldEqual(blankHbmArray.name); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.optimisticlock.ShouldEqual(arrayMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.optimisticlock.ShouldEqual(blankHbmArray.optimisticlock); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(string))); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.persister.ShouldEqual(arrayMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.persister.ShouldEqual(blankHbmArray.persister); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.schema.ShouldEqual(arrayMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.schema.ShouldEqual(blankHbmArray.schema); + } + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.table.ShouldEqual(arrayMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.table.ShouldEqual(blankHbmArray.table); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.where.ShouldEqual(arrayMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.where.ShouldEqual(blankHbmArray.where); + } + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.subselect.Text.ShouldEqual(new string[] { arrayMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't array anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.subselect.ShouldEqual(blankHbmArray.subselect); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var arrayMapping = CollectionMapping.Array(); + arrayMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmArray = converter.Convert(arrayMapping); + convertedHbmArray.mutable.ShouldEqual(arrayMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var arrayMapping = CollectionMapping.Array(); + // Don't set anything on the original mapping + var convertedHbmArray = converter.Convert(arrayMapping); + var blankHbmArray = new HbmArray(); + convertedHbmArray.mutable.ShouldEqual(blankHbmArray.mutable); + } + + #endregion Base collection attribute value field tests + + #region Type-specific collection attribute value field tests + + // No tests for this type + + #endregion Type-specific collection attribute value field tests + + #region Base collection converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Array(), + (arrayMapping, keyMapping) => arrayMapping.Set(fluent => fluent.Key, Layer.Defaults, keyMapping), + hbmArray => hbmArray.key); + } + + [Test] + public void ShouldConvertICollectionRelationship_OneToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Array(), + () => new OneToManyMapping(), + (arrayMapping, icrMapping) => arrayMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmArray => hbmArray.Item1); + } + + [Test] + public void ShouldConvertICollectionRelationship_ManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Array(), + () => new ManyToManyMapping(), + (arrayMapping, icrMapping) => arrayMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmArray => hbmArray.Item1); + } + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Array(), + (arrayMapping, cacheMapping) => arrayMapping.Set(fluent => fluent.Cache, Layer.Defaults, cacheMapping), + hbmArray => hbmArray.cache); + } + + [Test] + public void ShouldConvertCompositeElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Array(), + (arrayMapping, compositeElementMapping) => arrayMapping.Set(fluent => fluent.CompositeElement, Layer.Defaults, compositeElementMapping), + hbmArray => hbmArray.Item1); + } + + [Test] + public void ShouldConvertElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Array(), + (arrayMapping, elementMapping) => arrayMapping.Set(fluent => fluent.Element, Layer.Defaults, elementMapping), + hbmArray => hbmArray.Item1); + } + + // HbmArray, unlike HbmList, doesn't support filters + /* + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => CollectionMapping.Array(), + (arrayMapping, filterMapping) => arrayMapping.AddFilter(filterMapping), + hbmArray => hbmArray.filter); + } + */ + + #endregion Base collection converter-based subobject tests + + #region Type-specific collection converter-based subobject tests + + [Test] + public void ShouldConvertIIndex_Index() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Array(), + () => new IndexMapping(), + (arrayMapping, indexMapping) => arrayMapping.Set(fluent => fluent.Index, Layer.Defaults, indexMapping), + hbmArray => hbmArray.Item); + } + + // No other index type allowed by HbmArray has a fluent mapping at this point + + #endregion Type-specific collection converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmBagConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmBagConverterTester.cs new file mode 100644 index 000000000..f74e86269 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmBagConverterTester.cs @@ -0,0 +1,492 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmBagConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Base collection attribute value field tests + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.access.ShouldEqual(bagMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.access.ShouldEqual(blankHbmBag.access); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.batchsize.ShouldEqual(bagMapping.BatchSize); + Assert.That(convertedHbmBag.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.batchsize.ShouldEqual(blankHbmBag.batchsize); + Assert.That(convertedHbmBag.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.cascade.ShouldEqual(bagMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.cascade.ShouldEqual(blankHbmBag.cascade); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.check.ShouldEqual(bagMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.check.ShouldEqual(blankHbmBag.check); + } + + [Test] + public void ShouldConvertCollectionTypeIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, new TypeReference("type")); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.collectiontype.ShouldEqual(bagMapping.CollectionType.ToString()); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfEmpty() + { + var bagMapping = CollectionMapping.Bag(); + // Set an explicitly empty type reference + bagMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, TypeReference.Empty); + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.collectiontype.ShouldEqual(blankHbmBag.collectiontype); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.collectiontype.ShouldEqual(blankHbmBag.collectiontype); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmCollectionFetchMode.Subselect; // Defaults to Select, so use something else to properly detect that it changes + + var bagMapping = CollectionMapping.Bag(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + bagMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmBag.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(bagMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.fetch.ShouldEqual(blankHbmBag.fetch); + Assert.That(convertedHbmBag.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_True() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Generic, Layer.Conventions, true); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.generic.ShouldEqual(bagMapping.Generic); + Assert.That(convertedHbmBag.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_False() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Generic, Layer.Conventions, false); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.generic.ShouldEqual(bagMapping.Generic); + Assert.That(convertedHbmBag.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldNotConvertGenericIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.generic.ShouldEqual(blankHbmBag.generic); + Assert.That(convertedHbmBag.genericSpecified.Equals(false), "Generic was marked as specified"); + } + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.inverse.ShouldEqual(bagMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.inverse.ShouldEqual(blankHbmBag.inverse); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var hbmLazy = HbmCollectionLazy.False; // Defaults to True, so use something else to properly detect that it changes + + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Lazy, Layer.Conventions, HbmCollectionConverter.FluentHbmLazyBiDict[hbmLazy]); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.lazy.ShouldEqual(hbmLazy); + Assert.That(convertedHbmBag.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + // Since it is enum-based, Lazy cannot contain any invalid values, so no need to test for that here + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.lazy.ShouldEqual(blankHbmBag.lazy); + Assert.That(convertedHbmBag.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.name.ShouldEqual(bagMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.name.ShouldEqual(blankHbmBag.name); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.optimisticlock.ShouldEqual(bagMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.optimisticlock.ShouldEqual(blankHbmBag.optimisticlock); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(string))); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.persister.ShouldEqual(bagMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.persister.ShouldEqual(blankHbmBag.persister); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.schema.ShouldEqual(bagMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.schema.ShouldEqual(blankHbmBag.schema); + } + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.table.ShouldEqual(bagMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.table.ShouldEqual(blankHbmBag.table); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.where.ShouldEqual(bagMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.where.ShouldEqual(blankHbmBag.where); + } + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.subselect.Text.ShouldEqual(new string[] { bagMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.subselect.ShouldEqual(blankHbmBag.subselect); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.mutable.ShouldEqual(bagMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.mutable.ShouldEqual(blankHbmBag.mutable); + } + + #endregion Base collection attribute value field tests + + #region Type-specific collection attribute value field tests + + [Test] + public void ShouldConvertOrderByIfPopulated() + { + var bagMapping = CollectionMapping.Bag(); + bagMapping.Set(fluent => fluent.OrderBy, Layer.Conventions, "ord"); + var convertedHbmBag = converter.Convert(bagMapping); + convertedHbmBag.orderby.ShouldEqual(bagMapping.OrderBy); + } + + [Test] + public void ShouldNotConvertOrderByIfNotPopulated() + { + var bagMapping = CollectionMapping.Bag(); + // Don't set anything on the original mapping + var convertedHbmBag = converter.Convert(bagMapping); + var blankHbmBag = new HbmBag(); + convertedHbmBag.orderby.ShouldEqual(blankHbmBag.orderby); + } + + #endregion Type-specific collection attribute value field tests + + #region Base collection converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Bag(), + (bagMapping, keyMapping) => bagMapping.Set(fluent => fluent.Key, Layer.Defaults, keyMapping), + hbmBag => hbmBag.key); + } + + [Test] + public void ShouldConvertICollectionRelationship_OneToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Bag(), + () => new OneToManyMapping(), + (bagMapping, icrMapping) => bagMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmBag => hbmBag.Item); + } + + [Test] + public void ShouldConvertICollectionRelationship_ManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Bag(), + () => new ManyToManyMapping(), + (bagMapping, icrMapping) => bagMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmBag => hbmBag.Item); + } + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Bag(), + (bagMapping, cacheMapping) => bagMapping.Set(fluent => fluent.Cache, Layer.Defaults, cacheMapping), + hbmBag => hbmBag.cache); + } + + [Test] + public void ShouldConvertCompositeElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Bag(), + (bagMapping, compositeElementMapping) => bagMapping.Set(fluent => fluent.CompositeElement, Layer.Defaults, compositeElementMapping), + hbmBag => hbmBag.Item); + } + + [Test] + public void ShouldConvertElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Bag(), + (bagMapping, elementMapping) => bagMapping.Set(fluent => fluent.Element, Layer.Defaults, elementMapping), + hbmBag => hbmBag.Item); + } + + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => CollectionMapping.Bag(), + (bagMapping, filterMapping) => bagMapping.AddFilter(filterMapping), + hbmBag => hbmBag.filter); + } + + #endregion Base collection converter-based subobject tests + + #region Type-specific collection converter-based subobject tests + + // No tests for this type + + #endregion Type-specific collection converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmBasicSubclassConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmBasicSubclassConverterTester.cs new file mode 100644 index 000000000..af4ebf381 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmBasicSubclassConverterTester.cs @@ -0,0 +1,466 @@ +using System; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmBasicSubclassConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Value field tests + + [Test] + public void ShouldConvertDiscriminatorValueIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.DiscriminatorValue, Layer.Conventions, "val"); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.discriminatorvalue.ShouldEqual(subclassMapping.DiscriminatorValue.ToString()); + } + + [Test] + public void ShouldNotConvertDiscriminatorValueIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.discriminatorvalue.ShouldEqual(blankHbmSubclass.discriminatorvalue); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.name.ShouldEqual(subclassMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.name.ShouldEqual(blankHbmSubclass.name); + } + + [Test] + public void ShouldConvertProxyIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Proxy, Layer.Conventions, "p"); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.proxy.ShouldEqual(subclassMapping.Proxy); + } + + [Test] + public void ShouldNotConvertProxyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.proxy.ShouldEqual(blankHbmSubclass.proxy); + } + + [Test] + public void ShouldConvertLazyIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, false); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.lazy.ShouldEqual(blankHbmSubclass.lazy); + Assert.That(convertedHbmSubclass.lazySpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertDynamicUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.DynamicUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.dynamicupdate.ShouldEqual(subclassMapping.DynamicUpdate); + } + + [Test] + public void ShouldNotConvertDynamicUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.dynamicupdate.ShouldEqual(blankHbmSubclass.dynamicupdate); + } + + [Test] + public void ShouldConvertDynamicInsertIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.DynamicInsert, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.dynamicinsert.ShouldEqual(subclassMapping.DynamicInsert); + } + + [Test] + public void ShouldNotConvertDynamicInsertIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.dynamicinsert.ShouldEqual(blankHbmSubclass.dynamicinsert); + } + + [Test] + public void ShouldConvertSelectBeforeUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.SelectBeforeUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.selectbeforeupdate.ShouldEqual(subclassMapping.SelectBeforeUpdate); + } + + [Test] + public void ShouldNotConvertSelectBeforeUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.selectbeforeupdate.ShouldEqual(blankHbmSubclass.selectbeforeupdate); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, true); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, false); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldNotConvertAbstractIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.@abstract.ShouldEqual(blankHbmSubclass.@abstract); + Assert.That(convertedHbmSubclass.abstractSpecified.Equals(false), "Abstract was marked as specified"); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "entity1"); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.entityname.ShouldEqual(subclassMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.entityname.ShouldEqual(blankHbmSubclass.entityname); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmSubclass = converter.Convert(subclassMapping); + convertedHbmSubclass.batchsize.ShouldEqual(subclassMapping.BatchSize.ToString()); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + // Don't set anything on the original mapping + var convertedHbmSubclass = converter.Convert(subclassMapping); + var blankHbmSubclass = new HbmSubclass(); + convertedHbmSubclass.batchsize.ShouldEqual(blankHbmSubclass.batchsize); + } + + #endregion Value field tests + + #region Converter-based subobject tests + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping, propertyMapping) => subclassMapping.AddProperty(propertyMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping, manyToOneMapping) => subclassMapping.AddReference(manyToOneMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping, oneToOneMapping) => subclassMapping.AddOneToOne(oneToOneMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => new ComponentMapping(ComponentType.Component), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => new ComponentMapping(ComponentType.DynamicComponent), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping, anyMapping) => subclassMapping.AddAny(anyMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => CollectionMapping.Map(), + (subclassMapping, mapMapping) => subclassMapping.AddCollection(mapMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => CollectionMapping.Set(), + (subclassMapping, setMapping) => subclassMapping.AddCollection(setMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => CollectionMapping.List(), + (subclassMapping, listMapping) => subclassMapping.AddCollection(listMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => CollectionMapping.Bag(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => CollectionMapping.Array(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmSubclass => hbmSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertJoins() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping, joinMapping) => subclassMapping.AddJoin(joinMapping), + hbmSubclass => hbmSubclass.join); + } + + [Test] + public void ShouldConvertSubclasses_Subclass() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => new SubclassMapping(SubclassType.Subclass), + (subclassMapping1, subclassMapping2) => subclassMapping1.AddSubclass(subclassMapping2), + hbmSubclass => hbmSubclass.subclass1); + } + + [Test] + public void ShouldConvertSubclasses_JoinedSubclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, joinedSubclassMapping) => subclassMapping.AddSubclass(joinedSubclassMapping), + hbmSubclass => hbmSubclass.subclass1) + ); + } + + [Test] + public void ShouldConvertSubclasses_UnionSubclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + () => new SubclassMapping(SubclassType.UnionSubclass), + (subclassMapping, unionSubclassMapping) => subclassMapping.AddSubclass(unionSubclassMapping), + hbmSubclass => hbmSubclass.subclass1) + ); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlInsert() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.Subclass), + () => new StoredProcedureMapping("sql-insert", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmSubclass => hbmSubclass.sqlinsert); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlUpdate() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.Subclass), + () => new StoredProcedureMapping("sql-update", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmSubclass => hbmSubclass.sqlupdate); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlDelete() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.Subclass), + () => new StoredProcedureMapping("sql-delete", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmSubclass => hbmSubclass.sqldelete); + } + + [Test] + public void ShouldConvertStoredProcedure_Unsupported() + { + var unsupportedSPType = "invalid"; + + // Set up a fake converter + var fakeConverter = A.Fake>(); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and FMain == FSub + HMain == HSub (e.g., subclasses-of-subclasses) we + // get the real converter for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate the subclass mapping and a stored procedure submapping with an unsupported sptype + var subclassMapping = new SubclassMapping(SubclassType.Subclass); + subclassMapping.AddStoredProcedure(new StoredProcedureMapping(unsupportedSPType, "")); + + // This should throw + Assert.Throws(() => converter.Convert(subclassMapping)); + + // We don't care if it made a call to the subobject conversion logic or not (it is low enough cost that it doesn't + // really matter in the case of failure, and some implementation approaches that uses this may be simpler). + } + + #endregion Converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmCacheConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCacheConverterTester.cs new file mode 100644 index 000000000..6900d115a --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCacheConverterTester.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmCacheConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertRegionIfPopulatedWithValidValue() + { + var cacheMapping = new CacheMapping(); + cacheMapping.Set(fluent => fluent.Region, Layer.Conventions, "region"); + var convertedHbmCache = converter.Convert(cacheMapping); + convertedHbmCache.region.ShouldEqual(cacheMapping.Region); + } + + [Test] + public void ShouldNotConvertRegionIfNotPopulated() + { + var cacheMapping = new CacheMapping(); + // Don't set the anything on the original mapping + var convertedHbmCache = converter.Convert(cacheMapping); + var blankHbmCache = new HbmCache(); + convertedHbmCache.region.ShouldEqual(blankHbmCache.region); + } + + [Test] + public void ShouldConvertUsageIfPopulatedWithValidValue() + { + var usage = HbmCacheUsage.Transactional; // Defaults to ReadOnly, so use this to ensure that we can detect changes + + var cacheMapping = new CacheMapping(); + var usageDict = new XmlLinkedEnumBiDictionary(); + cacheMapping.Set(fluent => fluent.Usage, Layer.Conventions, usageDict[usage]); + var convertedHbmCache = converter.Convert(cacheMapping); + convertedHbmCache.usage.ShouldEqual(usage); + } + + [Test] + public void ShouldFailToConvertUsageIfPopulatedWithInvalidValue() + { + var cacheMapping = new CacheMapping(); + cacheMapping.Set(fluent => fluent.Usage, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(cacheMapping)); + } + + [Test] + public void ShouldNotConvertUsageIfNotPopulated() + { + var cacheMapping = new CacheMapping(); + // Don't set the anything on the original mapping + var convertedHbmCache = converter.Convert(cacheMapping); + var blankHbmCache = new HbmCache(); + convertedHbmCache.usage.ShouldEqual(blankHbmCache.usage); + } + + [Test] + public void ShouldConvertIncludeIfPopulatedWithValidValue() + { + var include = HbmCacheInclude.NonLazy; // Defaults to All, so use this to ensure that we can detect changes + + var cacheMapping = new CacheMapping(); + var includeDict = new XmlLinkedEnumBiDictionary(); + cacheMapping.Set(fluent => fluent.Include, Layer.Conventions, includeDict[include]); + var convertedHbmCache = converter.Convert(cacheMapping); + convertedHbmCache.include.ShouldEqual(include); + } + + [Test] + public void ShouldFailToConvertIncludeIfPopulatedWithInvalidValue() + { + var cacheMapping = new CacheMapping(); + cacheMapping.Set(fluent => fluent.Include, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(cacheMapping)); + } + + [Test] + public void ShouldNotConvertIncludeIfNotPopulated() + { + var cacheMapping = new CacheMapping(); + // Don't set the anything on the original mapping + var convertedHbmCache = converter.Convert(cacheMapping); + var blankHbmCache = new HbmCache(); + convertedHbmCache.include.ShouldEqual(blankHbmCache.include); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmClassConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmClassConverterTester.cs new file mode 100644 index 000000000..666fdeda5 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmClassConverterTester.cs @@ -0,0 +1,705 @@ +using System; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmClassConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Value field tests + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.table.ShouldEqual(classMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.table.ShouldEqual(blankHbmClass.table); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.schema.ShouldEqual(classMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.schema.ShouldEqual(blankHbmClass.schema); + } + + [Test] + public void ShouldConvertDiscriminatorValueIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.DiscriminatorValue, Layer.Conventions, 0); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.discriminatorvalue.ShouldEqual(classMapping.DiscriminatorValue.ToString()); + } + + [Test] + public void ShouldNotConvertDiscriminatorValueIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.discriminatorvalue.ShouldEqual(blankHbmClass.discriminatorvalue); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so we have to set it false here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.mutable.ShouldEqual(classMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.mutable.ShouldEqual(blankHbmClass.mutable); + } + + [Test] + public void ShouldConvertPolymorphismIfPopulatedWithValidValue() + { + var polymorphism = HbmPolymorphismType.Explicit; // Defaults to Implicit, so use something else to properly detect that it changes + + var classMapping = new ClassMapping(); + var polyDict = new XmlLinkedEnumBiDictionary(); + classMapping.Set(fluent => fluent.Polymorphism, Layer.Conventions, polyDict[polymorphism]); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.polymorphism.ShouldEqual(polymorphism); + } + + [Test] + public void ShouldFailToConvertPolymorphismIfPopulatedWithInvalidValue() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Polymorphism, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(classMapping)); + } + + [Test] + public void ShouldNotConvertPolymorphismIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.polymorphism.ShouldEqual(blankHbmClass.polymorphism); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Persister, Layer.Conventions, "p"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.persister.ShouldEqual(classMapping.Persister); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.persister.ShouldEqual(blankHbmClass.persister); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.where.ShouldEqual(classMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.where.ShouldEqual(blankHbmClass.where); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.batchsize.ShouldEqual(classMapping.BatchSize); + Assert.That(convertedHbmClass.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.batchsize.ShouldEqual(blankHbmClass.batchsize); + Assert.That(convertedHbmClass.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulatedWithValidValue() + { + var optimisticlock = HbmOptimisticLockMode.Dirty; // Defaults to Version, so use something else to properly detect that it changes + + var classMapping = new ClassMapping(); + var polyDict = new XmlLinkedEnumBiDictionary(); + classMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, polyDict[optimisticlock]); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.optimisticlock.ShouldEqual(optimisticlock); + } + + [Test] + public void ShouldFailToConvertOptimisticLockIfPopulatedWithInvalidValue() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(classMapping)); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.optimisticlock.ShouldEqual(blankHbmClass.optimisticlock); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.check.ShouldEqual(classMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.check.ShouldEqual(blankHbmClass.check); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.name.ShouldEqual(classMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.name.ShouldEqual(blankHbmClass.name); + } + + [Test] + public void ShouldConvertProxyIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Proxy, Layer.Conventions, "p"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.proxy.ShouldEqual(classMapping.Proxy); + } + + [Test] + public void ShouldNotConvertProxyIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.proxy.ShouldEqual(blankHbmClass.proxy); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.lazy.ShouldEqual(classMapping.Lazy); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.lazy.ShouldEqual(blankHbmClass.lazy); + } + + [Test] + public void ShouldConvertDynamicUpdateIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.DynamicUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.dynamicupdate.ShouldEqual(classMapping.DynamicUpdate); + } + + [Test] + public void ShouldNotConvertDynamicUpdateIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.dynamicupdate.ShouldEqual(blankHbmClass.dynamicupdate); + } + + [Test] + public void ShouldConvertDynamicInsertIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.DynamicInsert, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.dynamicinsert.ShouldEqual(classMapping.DynamicInsert); + } + + [Test] + public void ShouldNotConvertDynamicInsertIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.dynamicinsert.ShouldEqual(blankHbmClass.dynamicinsert); + } + + [Test] + public void ShouldConvertSelectBeforeUpdateIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.SelectBeforeUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.selectbeforeupdate.ShouldEqual(classMapping.SelectBeforeUpdate); + } + + [Test] + public void ShouldNotConvertSelectBeforeUpdateIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.selectbeforeupdate.ShouldEqual(blankHbmClass.selectbeforeupdate); + } + + [Test] + public void ShouldConvertAbstractIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Abstract, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.@abstract.ShouldEqual(classMapping.Abstract); + Assert.That(convertedHbmClass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldNotConvertAbstractIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.@abstract.ShouldEqual(blankHbmClass.@abstract); + Assert.That(convertedHbmClass.abstractSpecified.Equals(false), "Abstract was marked as specified"); + } + + [Test] + public void ShouldConvertSchemaActionIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.SchemaAction, Layer.Conventions, "none"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.schemaaction.ShouldEqual(classMapping.SchemaAction); + } + + [Test] + public void ShouldNotConvertSchemaActionIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.schemaaction.ShouldEqual(blankHbmClass.schemaaction); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "entity1"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.entityname.ShouldEqual(classMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.entityname.ShouldEqual(blankHbmClass.entityname); + } + + #endregion Value field tests + + #region Non-converter-based subobject tests + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var classMapping = new ClassMapping(); + classMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmClass = converter.Convert(classMapping); + convertedHbmClass.subselect.Text.ShouldEqual(new string[] { classMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var classMapping = new ClassMapping(); + // Don't set anything on the original mapping + var convertedHbmClass = converter.Convert(classMapping); + var blankHbmClass = new HbmClass(); + convertedHbmClass.subselect.ShouldEqual(blankHbmClass.subselect); + } + + #endregion Non-converter-based subobject tests + + #region Converter-based subobject tests + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (classMapping, cacheMapping) => classMapping.Set(fluent => fluent.Cache, Layer.Conventions, cacheMapping), + hbmClass => hbmClass.cache); + } + + [Test] + public void ShouldConvertIIdentity_Id() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => new IdMapping(), + (classMapping, iidMapping) => classMapping.Set(fluent => fluent.Id, Layer.Conventions, iidMapping), + hbmClass => hbmClass.Item); + } + + [Test] + public void ShouldConvertIIdentity_CompositeId() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => new CompositeIdMapping(), + (classMapping, iidMapping) => classMapping.Set(fluent => fluent.Id, Layer.Conventions, iidMapping), + hbmClass => hbmClass.Item); + } + + [Test] + public void ShouldConvertNaturalId() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (classMapping, naturalIdMapping) => classMapping.Set(fluent => fluent.NaturalId, Layer.Conventions, naturalIdMapping), + hbmClass => hbmClass.naturalid); + } + + [Test] + public void ShouldConvertVersion() + { + ShouldConvertSubobjectAsLooselyTypedField( + (classMapping, versionMapping) => classMapping.Set(fluent => fluent.Version, Layer.Conventions, versionMapping), + hbmClass => hbmClass.Item1); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (classMapping, propertyMapping) => classMapping.AddProperty(propertyMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (classMapping, manyToOneMapping) => classMapping.AddReference(manyToOneMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (classMapping, oneToOneMapping) => classMapping.AddOneToOne(oneToOneMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (classMapping, componentMapping) => classMapping.AddComponent(componentMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (classMapping, componentMapping) => classMapping.AddComponent(componentMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (classMapping, anyMapping) => classMapping.AddAny(anyMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Map(), + (classMapping, mapMapping) => classMapping.AddCollection(mapMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Set(), + (classMapping, setMapping) => classMapping.AddCollection(setMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.List(), + (classMapping, listMapping) => classMapping.AddCollection(listMapping), + hbmClass => hbmClass.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Bag(), + (classMapping, bagMapping) => classMapping.AddCollection(bagMapping), + hbmClass => hbmClass.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Array(), + (classMapping, bagMapping) => classMapping.AddCollection(bagMapping), + hbmClass => hbmClass.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertJoins() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (classMapping, joinMapping) => classMapping.AddJoin(joinMapping), + hbmClass => hbmClass.Items1); + } + + [Test] + public void ShouldConvertSubclasses_Subclass() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.Subclass), + (classMapping, subclassMapping) => classMapping.AddSubclass(subclassMapping), + hbmClass => hbmClass.Items1); + } + + [Test] + public void ShouldConvertSubclasses_JoinedSubclass() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (classMapping, joinedSubclassMapping) => classMapping.AddSubclass(joinedSubclassMapping), + hbmClass => hbmClass.Items1); + } + + [Test] + public void ShouldConvertSubclasses_UnionSubclass() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + (classMapping, unionSubclassMapping) => classMapping.AddSubclass(unionSubclassMapping), + hbmClass => hbmClass.Items1); + } + + [Test] + public void ShouldConvertDiscriminator() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (classMapping, discriminatorMapping) => classMapping.Set(fluent => fluent.Discriminator, Layer.Conventions, discriminatorMapping), + hbmClass => hbmClass.discriminator); + } + + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (classMapping, filterMapping) => classMapping.AddFilter(filterMapping), + hbmClass => hbmClass.filter); + } + + [Test] + public void ShouldConvertTuplizers() + { + // Note that this is singular on the source but plural on the target + ShouldConvertSubobjectsAsStrictlyTypedArray( + (classMapping, tuplizerMapping) => classMapping.Set(fluent => fluent.Tuplizer, Layer.Conventions, tuplizerMapping), + hbmClass => hbmClass.tuplizer); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlInsert() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-insert", ""), + (classMapping, storedProcedureMapping) => classMapping.AddStoredProcedure(storedProcedureMapping), + hbmClass => hbmClass.sqlinsert); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlUpdate() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-update", ""), + (classMapping, storedProcedureMapping) => classMapping.AddStoredProcedure(storedProcedureMapping), + hbmClass => hbmClass.sqlupdate); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlDelete() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-delete", ""), + (classMapping, storedProcedureMapping) => classMapping.AddStoredProcedure(storedProcedureMapping), + hbmClass => hbmClass.sqldelete); + } + + [Test] + public void ShouldConvertStoredProcedure_Unsupported() + { + var unsupportedSPType = "invalid"; + + // Set up a fake converter + var fakeConverter = A.Fake>(); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so that it will use the fake implementation) + var container = new HbmConverterContainer(); + container.Register>(cnvrt => fakeConverter); + converter = container.Resolve>(); + + // Allocate the class mapping and a stored procedure submapping with an unsupported sptype + var classMapping = new ClassMapping(); + classMapping.AddStoredProcedure(new StoredProcedureMapping(unsupportedSPType, "")); + + // This should throw + Assert.Throws(() => converter.Convert(classMapping)); + + // We don't care if it made a call to the subobject conversion logic or not (it is low enough cost that it doesn't + // really matter in the case of failure, and some implementation approaches that uses this may be simpler). + } + + #endregion Converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionConverterTester.cs new file mode 100644 index 000000000..29fe1d72d --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionConverterTester.cs @@ -0,0 +1,57 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmCollectionConverterTester + { + // No use for the normal setup method to populate the container, since no test uses it + + [Test] + public void ShouldProcessBagAsBag() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => CollectionMapping.Bag() + ); + } + + [Test] + public void ShouldProcessListAsList() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => CollectionMapping.List() + ); + } + + [Test] + public void ShouldProcessSetAsSet() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => CollectionMapping.Set() + ); + } + + [Test] + public void ShouldProcessMapAsMap() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => CollectionMapping.Map() + ); + } + + [Test] + public void ShouldProcessArrayAsArray() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => CollectionMapping.Array() + ); + } + + /* Unfortunately, there is no good way to test the "fail if passed something unsupported" logic, because we cannot + * generate a "bad" Collection type (it is an enum) and we want to support all of the real ones. + */ + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionRelationshipConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionRelationshipConverterTester.cs new file mode 100644 index 000000000..7cf161572 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCollectionRelationshipConverterTester.cs @@ -0,0 +1,25 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmCollectionRelationshipConverterTester + { + // No use for the normal setup method to populate the container, since no test uses it + + [Test] + public void ShouldProcessOneToManyAsOneToMany() + { + ShouldConvertSpecificHbmForMappingChild(); + } + + [Test] + public void ShouldProcessManyToManyAsManyToMany() + { + ShouldConvertSpecificHbmForMappingChild(); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmColumnConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmColumnConverterTester.cs new file mode 100644 index 000000000..189895262 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmColumnConverterTester.cs @@ -0,0 +1,233 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmColumnConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Check, Layer.Conventions, "ck"); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.check.ShouldEqual(columnMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.check.ShouldEqual(blankHbmColumn.check); + } + + [Test] + public void ShouldConvertDefaultIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Default, Layer.Conventions, "df"); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.@default.ShouldEqual(columnMapping.Default); + } + + [Test] + public void ShouldNotConvertDefaultIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.@default.ShouldEqual(blankHbmColumn.@default); + } + + [Test] + public void ShouldConvertIndexIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Index, Layer.Conventions, "ix"); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.index.ShouldEqual(columnMapping.Index); + } + + [Test] + public void ShouldNotConvertIndexIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.index.ShouldEqual(blankHbmColumn.index); + } + + [Test] + public void ShouldConvertLengthIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Length, Layer.Conventions, 10); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.length.ShouldEqual(columnMapping.Length.ToString()); + } + + [Test] + public void ShouldNotConvertLengthIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.length.ShouldEqual(blankHbmColumn.length); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.name.ShouldEqual(columnMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.name.ShouldEqual(blankHbmColumn.name); + } + + [Test] + public void ShouldConvertNotNullIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.NotNull, Layer.Conventions, true); // Defaults to false, so use true so that we can detect changes + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.notnull.ShouldEqual(columnMapping.NotNull); + Assert.That(convertedHbmColumn.notnullSpecified.Equals(true), "NotNull was not marked as specified"); + } + + [Test] + public void ShouldNotConvertNotNullIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.notnull.ShouldEqual(blankHbmColumn.notnull); + Assert.That(convertedHbmColumn.notnullSpecified.Equals(false), "NotNull was marked as specified"); + } + + [Test] + public void ShouldConvertSqlTypeIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.SqlType, Layer.Conventions, "type"); // FIXME: Is this a realistic value? + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.sqltype.ShouldEqual(columnMapping.SqlType); + } + + [Test] + public void ShouldNotConvertSqlTypeIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.sqltype.ShouldEqual(blankHbmColumn.sqltype); + } + + [Test] + public void ShouldConvertUniqueIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Unique, Layer.Conventions, true); // Defaults to false, so use true so that we can detect changes + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.unique.ShouldEqual(columnMapping.Unique); + Assert.That(convertedHbmColumn.uniqueSpecified.Equals(true), "Unique was not marked as specified"); + } + + [Test] + public void ShouldNotConvertUniqueIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.unique.ShouldEqual(blankHbmColumn.unique); + Assert.That(convertedHbmColumn.uniqueSpecified.Equals(false), "Unique was marked as specified"); + } + + [Test] + public void ShouldConvertUniqueKeyIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.UniqueKey, Layer.Conventions, "uk"); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.uniquekey.ShouldEqual(columnMapping.UniqueKey); + } + + [Test] + public void ShouldNotConvertUniqueKeyIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.uniquekey.ShouldEqual(blankHbmColumn.uniquekey); + } + + [Test] + public void ShouldConvertPrecisionIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Precision, Layer.Conventions, 10); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.precision.ShouldEqual(columnMapping.Precision.ToString()); + } + + [Test] + public void ShouldNotConvertPrecisionIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.precision.ShouldEqual(blankHbmColumn.precision); + } + + [Test] + public void ShouldConvertScaleIfPopulated() + { + var columnMapping = new ColumnMapping(); + columnMapping.Set(fluent => fluent.Scale, Layer.Conventions, 10); + var convertedHbmColumn = converter.Convert(columnMapping); + convertedHbmColumn.scale.ShouldEqual(columnMapping.Scale.ToString()); + } + + [Test] + public void ShouldNotConvertScaleIfNotPopulated() + { + var columnMapping = new ColumnMapping(); + // Don't set anything on the original mapping + var convertedHbmColumn = converter.Convert(columnMapping); + var blankHbmColumn = new HbmColumn(); + convertedHbmColumn.scale.ShouldEqual(blankHbmColumn.scale); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentBasedConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentBasedConverterTester.cs new file mode 100644 index 000000000..57fc6f3f4 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentBasedConverterTester.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using FakeItEasy; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmComponentBasedConverterTester + { + [Test] + public void ShouldConvertComponentAsComponent() + { + ShouldConvertSpecificHbmForMapping( + () => new ComponentMapping(ComponentType.Component) + ); + } + + [Test] + public void ShouldConvertDynamicComponentAsDynamicComponent() + { + ShouldConvertSpecificHbmForMapping( + () => new ComponentMapping(ComponentType.DynamicComponent) + ); + } + + [Test] + public void ShouldConvertExternalComponentAsComponent() + { + ShouldConvertSpecificHbmForMapping( + () => new ExternalComponentMapping(ComponentType.Component) + ); + } + + [Test] + public void ShouldConvertDynamicExternalComponentAsDynamicComponent() + { + ShouldConvertSpecificHbmForMapping( + () => new ExternalComponentMapping(ComponentType.DynamicComponent) + ); + } + + /* Unfortunately, there is no good way to test the "fail if passed something unsupported" logic, because we cannot + * generate a "bad" ComponentType and we want to support all of the real ones. + */ + + [Test] + public void ShouldConvertReferenceComponentAsComponent() + { + /* This test requires somewhat specialized setup. Specifically, rather than looking for a handoff of the entire + * mapping to an IHbmConverter for some specific X, we look for a handoff of the merged + * model to an IHbmConverter. This is due to how the existing code structures things. + */ + + // Set up a fake converter that registers any instances it generates and returns in a list + var generatedHbms = new List(); + var fakeConverter = A.Fake>(); + A.CallTo(() => fakeConverter.Convert(A.Ignored)).ReturnsLazily(fSub => + { + var hbm = new HbmComponent(); + generatedHbms.Add(hbm); + return hbm; + }); + + // Set up a custom container with the fake IComponentMapping->object converter registered, and obtain our main + // converter from it (so that it will use the fake implementation). Note that we do the resolution _before_ we + // register the fake, so that in cases where we are doing recursive types and HSuper == H we get the real converter + // for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + IHbmConverter converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate an instance of the descendant type, but explicitly label it as the ancestor type to ensure that we pass it correctly + ReferenceComponentMapping mapping = CreateReferenceComponentInstance(); + + // Now try to convert it + var convertedHbm = converter.Convert(mapping); + + // Check that the expected converter was invoked *with the merged model* the correct number of times and that the returned value is the converted instance + A.CallTo(() => fakeConverter.Convert(mapping.MergedModel)).MustHaveHappened(Repeated.Exactly.Once); // Do this first since it guarantees the list should have exactly one item + convertedHbm.ShouldEqual(generatedHbms[0]); + } + + // NOTE: Because reference components require the target component type, they don't make any sense as dynamic components + // (and I'm not certain why the constructor even allows for it; nothing in the code base appears to use it). Therefore, + // we don't currently test for it here. If a well-defined use case is added later, a matching test should be added here. + + private ReferenceComponentMapping CreateReferenceComponentInstance() + { + var property = new DummyPropertyInfo("ComponentProperty", typeof(ComponentTarget)).ToMember(); + var instance = new ReferenceComponentMapping(ComponentType.Component, property, typeof(ComponentTarget), typeof(Target), null); + instance.AssociateExternalMapping(new ExternalComponentMapping(ComponentType.Component)); + return instance; + } + + private class Target + { + public int Id { get; set; } + public ComponentTarget ComponentProperty { get; set; } + } + + private class ComponentTarget + { + public string StringProperty { get; set; } + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentConverterTester.cs new file mode 100644 index 000000000..e8042068f --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmComponentConverterTester.cs @@ -0,0 +1,284 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmComponentConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.name.ShouldEqual(componentMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.name.ShouldEqual(blankHbmComponent.name); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.access.ShouldEqual(componentMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.access.ShouldEqual(blankHbmComponent.access); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("class")); + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.@class.ShouldEqual(componentMapping.Class); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.@class.ShouldEqual(blankHbmComponent.@class); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Update, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.update.ShouldEqual(componentMapping.Update); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.update.ShouldEqual(blankHbmComponent.update); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Insert, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.insert.ShouldEqual(componentMapping.Insert); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.insert.ShouldEqual(blankHbmComponent.insert); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.lazy.ShouldEqual(componentMapping.Lazy); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.lazy.ShouldEqual(blankHbmComponent.lazy); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + componentMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmComponent = converter.Convert(componentMapping); + convertedHbmComponent.optimisticlock.ShouldEqual(componentMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var componentMapping = new ComponentMapping(ComponentType.Component); + // Don't set anything on the original mapping + var convertedHbmComponent = converter.Convert(componentMapping); + var blankHbmComponent = new HbmComponent(); + convertedHbmComponent.optimisticlock.ShouldEqual(blankHbmComponent.optimisticlock); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => new ComponentMapping(ComponentType.Component), + (componentMapping1, componentMapping2) => componentMapping1.AddComponent(componentMapping2), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => new ComponentMapping(ComponentType.DynamicComponent), + (componentMapping, dynamicComponentMapping) => componentMapping.AddComponent(dynamicComponentMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertParent() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new ComponentMapping(ComponentType.Component), + (componentMapping, parentMapping) => componentMapping.Set(fluent => fluent.Parent, Layer.Conventions, parentMapping), + hbmComponent => hbmComponent.parent); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (componentMapping, propertyMapping) => componentMapping.AddProperty(propertyMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (componentMapping, manyToOneMapping) => componentMapping.AddReference(manyToOneMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (componentMapping, oneToOneMapping) => componentMapping.AddOneToOne(oneToOneMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (componentMapping, anyMapping) => componentMapping.AddAny(anyMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => CollectionMapping.Map(), + (componentMapping, mapMapping) => componentMapping.AddCollection(mapMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => CollectionMapping.Set(), + (componentMapping, setMapping) => componentMapping.AddCollection(setMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => CollectionMapping.Bag(), + (componentMapping, bagMapping) => componentMapping.AddCollection(bagMapping), + hbmComponent => hbmComponent.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => CollectionMapping.List(), + (componentMapping, listMapping) => componentMapping.AddCollection(listMapping), + hbmComponent => hbmComponent.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + () => CollectionMapping.Array(), + (componentMapping, bagMapping) => componentMapping.AddCollection(bagMapping), + hbmComponent => hbmComponent.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Not yet fully reviewed"); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeElementConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeElementConverterTester.cs new file mode 100644 index 000000000..9ed577758 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeElementConverterTester.cs @@ -0,0 +1,73 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmCompositeElementConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var compositeElementMapping = new CompositeElementMapping(); + compositeElementMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("t")); + var convertedHbmCompositeElement = converter.Convert(compositeElementMapping); + convertedHbmCompositeElement.@class.ShouldEqual(compositeElementMapping.Class); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var compositeElementMapping = new CompositeElementMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeElement = converter.Convert(compositeElementMapping); + var blankHbmCompositeElement = new HbmCompositeElement(); + convertedHbmCompositeElement.@class.ShouldEqual(blankHbmCompositeElement.@class); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (compositeElementMapping, propertyMapping) => compositeElementMapping.AddProperty(propertyMapping), + hbmCompositeElement => hbmCompositeElement.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (compositeElementMapping, manyToOneMapping) => compositeElementMapping.AddReference(manyToOneMapping), + hbmCompositeElement => hbmCompositeElement.Items); + } + + [Test] + public void ShouldConvertNestedCompositeElements() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (compositeElementMapping, nestedCompositeElementMapping) => compositeElementMapping.AddCompositeElement(nestedCompositeElementMapping), + hbmCompositeElement => hbmCompositeElement.Items); + } + + [Test] + public void ShouldConvertParent() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (compositeElementMapping, parentMapping) => compositeElementMapping.Set(fluent => fluent.Parent, Layer.Defaults, parentMapping), + hbmCompositeElement => hbmCompositeElement.parent); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeIdConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeIdConverterTester.cs new file mode 100644 index 000000000..347a0569d --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmCompositeIdConverterTester.cs @@ -0,0 +1,145 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmCompositeIdConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + compositeIdMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + convertedHbmCompositeId.access.ShouldEqual(compositeIdMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + var blankHbmCompositeId = new HbmCompositeId(); + convertedHbmCompositeId.access.ShouldEqual(blankHbmCompositeId.access); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + compositeIdMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + convertedHbmCompositeId.name.ShouldEqual(compositeIdMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + var blankHbmCompositeId = new HbmCompositeId(); + convertedHbmCompositeId.name.ShouldEqual(blankHbmCompositeId.name); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + compositeIdMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference(typeof(HbmCompositeIdConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + convertedHbmCompositeId.@class.ShouldEqual(compositeIdMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + var blankHbmCompositeId = new HbmCompositeId(); + convertedHbmCompositeId.@class.ShouldEqual(blankHbmCompositeId.@class); + } + + [Test] + public void ShouldConvertMappedIfPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + compositeIdMapping.Set(fluent => fluent.Mapped, Layer.Conventions, true); // Defaults to false, so we set it true in order to ensure that we can detect that it changed + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + convertedHbmCompositeId.mapped.ShouldEqual(compositeIdMapping.Mapped); + } + + [Test] + public void ShouldNotConvertMappedIfNotPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + var blankHbmCompositeId = new HbmCompositeId(); + convertedHbmCompositeId.mapped.ShouldEqual(blankHbmCompositeId.mapped); + } + + [Test] + public void ShouldConvertUnsavedValueIfPopulatedWithValidValue() + { + var unsavedValue = HbmUnsavedValueType.Any; // Defaults to Undefined, so use something else to properly detect that it changes + + var compositeIdMapping = new CompositeIdMapping(); + var unsavedDict = new XmlLinkedEnumBiDictionary(); + compositeIdMapping.Set(fluent => fluent.UnsavedValue, Layer.Conventions, unsavedDict[unsavedValue]); + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + convertedHbmCompositeId.unsavedvalue.ShouldEqual(unsavedValue); + } + + [Test] + public void ShouldFailToConvertUnsavedValueIfPopulatedWithInvalidValue() + { + var compositeIdMapping = new CompositeIdMapping(); + compositeIdMapping.Set(fluent => fluent.UnsavedValue, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(compositeIdMapping)); + } + + [Test] + public void ShouldNotConvertUnsavedValueIfNotPopulated() + { + var compositeIdMapping = new CompositeIdMapping(); + // Don't set anything on the original mapping + var convertedHbmCompositeId = converter.Convert(compositeIdMapping); + var blankHbmCompositeId = new HbmCompositeId(); + convertedHbmCompositeId.unsavedvalue.ShouldEqual(blankHbmCompositeId.unsavedvalue); + } + + [Test] + public void ShouldConvertKeyProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (compositeIdMapping, keyPropertyMapping) => compositeIdMapping.AddKey(keyPropertyMapping), + hbmCompositeId => hbmCompositeId.Items); + } + + [Test] + public void ShouldConvertKeyManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (compositeIdMapping, keyManyToOneMapping) => compositeIdMapping.AddKey(keyManyToOneMapping), + hbmCompositeId => hbmCompositeId.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmConverterContainerTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmConverterContainerTester.cs new file mode 100644 index 000000000..c34fcce6b --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmConverterContainerTester.cs @@ -0,0 +1,40 @@ +using System.Linq; +using FluentNHibernate.Infrastructure; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmConverterContainerTester + { + private HbmConverterContainer container; + + [SetUp] + public void CreateContainer() + { + container = new HbmConverterContainer(); + } + + [Test] + public void ShouldResolveAllConverters() + { + var converters = from type in typeof(IHbmConverter<,>).Assembly.GetTypes() + from interfaceType in type.GetInterfaces() + where !type.IsAbstract && interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(IHbmConverter<,>) + select interfaceType; + + foreach (var type in converters) + { + try + { + container.Resolve(type); + } + catch (ResolveException resolveEx) + { + throw new AssertionException(string.Format("Unable to resolve converter {0}", type), resolveEx); + } + } + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmDiscriminatorConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmDiscriminatorConverterTester.cs new file mode 100644 index 000000000..95b762bfa --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmDiscriminatorConverterTester.cs @@ -0,0 +1,108 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using FluentNHibernate.Mapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmDiscriminatorConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertForceIfPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + discriminatorMapping.Set(fluent => fluent.Force, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + convertedHbmDiscriminator.force.ShouldEqual(discriminatorMapping.Force); + } + + [Test] + public void ShouldNotConvertForceIfNotPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + // Don't set anything on the original mapping + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + var blankHbmDiscriminator = new HbmDiscriminator(); + convertedHbmDiscriminator.force.ShouldEqual(blankHbmDiscriminator.force); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + discriminatorMapping.Set(fluent => fluent.Insert, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + convertedHbmDiscriminator.insert.ShouldEqual(discriminatorMapping.Insert); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + // Don't set anything on the original mapping + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + var blankHbmDiscriminator = new HbmDiscriminator(); + convertedHbmDiscriminator.insert.ShouldEqual(blankHbmDiscriminator.insert); + } + + [Test] + public void ShouldConvertFormulaIfPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + discriminatorMapping.Set(fluent => fluent.Formula, Layer.Conventions, "f"); + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + convertedHbmDiscriminator.formula.ShouldEqual(discriminatorMapping.Formula); + } + + [Test] + public void ShouldNotConvertFormulaIfNotPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + // Don't set anything on the original mapping + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + var blankHbmDiscriminator = new HbmDiscriminator(); + convertedHbmDiscriminator.formula.ShouldEqual(blankHbmDiscriminator.formula); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var typeRef = new TypeReference(typeof(HbmDiscriminatorConverterTester)); + + var discriminatorMapping = new DiscriminatorMapping(); + discriminatorMapping.Set(fluent => fluent.Type, Layer.Conventions, typeRef); // Can be any class, this one is just guaranteed to exist + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + convertedHbmDiscriminator.type.ShouldEqual(TypeMapping.GetTypeString(typeRef.GetUnderlyingSystemType())); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var discriminatorMapping = new DiscriminatorMapping(); + // Don't set anything on the original mapping + var convertedHbmDiscriminator = converter.Convert(discriminatorMapping); + var blankHbmDiscriminator = new HbmDiscriminator(); + convertedHbmDiscriminator.type.ShouldEqual(blankHbmDiscriminator.type); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectAsLooselyTypedField( + (discriminatorMapping, columnMapping) => discriminatorMapping.AddColumn(Layer.Defaults, columnMapping), + hbmDiscriminator => hbmDiscriminator.Item); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmDynamicComponentConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmDynamicComponentConverterTester.cs new file mode 100644 index 000000000..d72a4b755 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmDynamicComponentConverterTester.cs @@ -0,0 +1,237 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmDynamicComponentConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + dynamicComponentMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + convertedHbmDynamicComponent.name.ShouldEqual(dynamicComponentMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + // Don't set anything on the original mapping + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + var blankHbmDynamicComponent = new HbmDynamicComponent(); + convertedHbmDynamicComponent.name.ShouldEqual(blankHbmDynamicComponent.name); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + dynamicComponentMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + convertedHbmDynamicComponent.access.ShouldEqual(dynamicComponentMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + // Don't set anything on the original mapping + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + var blankHbmDynamicComponent = new HbmDynamicComponent(); + convertedHbmDynamicComponent.access.ShouldEqual(blankHbmDynamicComponent.access); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + dynamicComponentMapping.Set(fluent => fluent.Update, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + convertedHbmDynamicComponent.update.ShouldEqual(dynamicComponentMapping.Update); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + // Don't set anything on the original mapping + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + var blankHbmDynamicComponent = new HbmDynamicComponent(); + convertedHbmDynamicComponent.update.ShouldEqual(blankHbmDynamicComponent.update); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + dynamicComponentMapping.Set(fluent => fluent.Insert, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + convertedHbmDynamicComponent.insert.ShouldEqual(dynamicComponentMapping.Insert); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + // Don't set anything on the original mapping + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + var blankHbmDynamicComponent = new HbmDynamicComponent(); + convertedHbmDynamicComponent.insert.ShouldEqual(blankHbmDynamicComponent.insert); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + dynamicComponentMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + convertedHbmDynamicComponent.optimisticlock.ShouldEqual(dynamicComponentMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var dynamicComponentMapping = new ComponentMapping(ComponentType.DynamicComponent); + // Don't set anything on the original mapping + var convertedHbmDynamicComponent = converter.Convert(dynamicComponentMapping); + var blankHbmDynamicComponent = new HbmDynamicComponent(); + convertedHbmDynamicComponent.optimisticlock.ShouldEqual(blankHbmDynamicComponent.optimisticlock); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => new ComponentMapping(ComponentType.Component), + (dynamicComponentMapping, componentMapping) => dynamicComponentMapping.AddComponent(componentMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => new ComponentMapping(ComponentType.DynamicComponent), + (dynamicComponentMapping1, dynamicComponentMapping2) => dynamicComponentMapping1.AddComponent(dynamicComponentMapping2), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (dynamicComponentMapping, propertyMapping) => dynamicComponentMapping.AddProperty(propertyMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (dynamicComponentMapping, manyToOneMapping) => dynamicComponentMapping.AddReference(manyToOneMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (dynamicComponentMapping, oneToOneMapping) => dynamicComponentMapping.AddOneToOne(oneToOneMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (dynamicComponentMapping, anyMapping) => dynamicComponentMapping.AddAny(anyMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => CollectionMapping.Map(), + (dynamicComponentMapping, mapMapping) => dynamicComponentMapping.AddCollection(mapMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => CollectionMapping.Set(), + (dynamicComponentMapping, setMapping) => dynamicComponentMapping.AddCollection(setMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => CollectionMapping.Bag(), + (dynamicComponentMapping, bagMapping) => dynamicComponentMapping.AddCollection(bagMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => CollectionMapping.List(), + (dynamicComponentMapping, listMapping) => dynamicComponentMapping.AddCollection(listMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + () => CollectionMapping.Array(), + (dynamicComponentMapping, bagMapping) => dynamicComponentMapping.AddCollection(bagMapping), + hbmDynamicComponent => hbmDynamicComponent.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Not yet fully reviewed"); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmElementConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmElementConverterTester.cs new file mode 100644 index 000000000..c62bda492 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmElementConverterTester.cs @@ -0,0 +1,68 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmElementConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var elementMapping = new ElementMapping(); + elementMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference("type")); + var convertedHbmElement = converter.Convert(elementMapping); + convertedHbmElement.type1.ShouldEqual(elementMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var elementMapping = new ElementMapping(); + // Don't set anything on the original mapping + var convertedHbmElement = converter.Convert(elementMapping); + var blankHbmElement = new HbmElement(); + convertedHbmElement.type1.ShouldEqual(blankHbmElement.type1); + } + + [Test] + public void ShouldConvertFormulaIfPopulated() + { + var elementMapping = new ElementMapping(); + elementMapping.Set(fluent => fluent.Formula, Layer.Conventions, "formula"); + var convertedHbmElement = converter.Convert(elementMapping); + convertedHbmElement.formula.ShouldEqual(elementMapping.Formula); + } + + [Test] + public void ShouldNotConvertFormulaIfNotPopulated() + { + var elementMapping = new ElementMapping(); + // Don't set anything on the original mapping + var convertedHbmElement = converter.Convert(elementMapping); + var blankHbmElement = new HbmElement(); + convertedHbmElement.formula.ShouldEqual(blankHbmElement.formula); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (elementMapping, columnMapping) => elementMapping.AddColumn(Layer.Conventions, columnMapping), + hbmElement => hbmElement.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterConverterTester.cs new file mode 100644 index 000000000..50fcd0f94 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterConverterTester.cs @@ -0,0 +1,67 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmFilterConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var filterMapping = new FilterMapping(); + filterMapping.Set(fluent => fluent.Name, Layer.Conventions, "sid"); + var convertedHbmFilter = converter.Convert(filterMapping); + convertedHbmFilter.name.ShouldEqual(filterMapping.Name); + } + + [Test] + public void ShouldConvertNameIfNotPopulated() + { + var filterMapping = new FilterMapping(); + // Don't set anything on the original mapping + var convertedHbmFilter = converter.Convert(filterMapping); + convertedHbmFilter.name.ShouldEqual(filterMapping.Name); + } + + [Test] + public void ShouldConvertConditionIfPopulated() + { + var filterMapping = new FilterMapping(); + filterMapping.Set(fluent => fluent.Condition, Layer.Conventions, "Fred = :george"); + var convertedHbmFilter = converter.Convert(filterMapping); + convertedHbmFilter.condition.ShouldEqual(filterMapping.Condition); + } + + [Test] + public void ShouldNotConvertConditionIfNotPopulated() + { + var filterMapping = new FilterMapping(); + // Don't set anything on the original mapping + var convertedHbmFilter = converter.Convert(filterMapping); + var blankHbmFilter = new HbmFilter(); + convertedHbmFilter.condition.ShouldEqual(blankHbmFilter.condition); + } + + [Test] + public void ShouldNotConvertConditionIfEmpty() + { + var filterMapping = new FilterMapping(); + filterMapping.Set(fluent => fluent.Condition, Layer.Conventions, ""); + var convertedHbmFilter = converter.Convert(filterMapping); + var blankHbmFilter = new HbmFilter(); + convertedHbmFilter.condition.ShouldEqual(blankHbmFilter.condition); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterDefinitionConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterDefinitionConverterTester.cs new file mode 100644 index 000000000..da1920b29 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmFilterDefinitionConverterTester.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NHibernate; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Type; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmFilterDefinitionConverterTester + { + private static KeyValuePair SAMPLE_FILTER_PARAM_1 = new KeyValuePair("george", NHibernateUtil.Int32); + private static KeyValuePair SAMPLE_FILTER_PARAM_2 = new KeyValuePair("fred", NHibernateUtil.Guid); + + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + filterDefinitionMapping.Set(fluent => fluent.Name, Layer.Conventions, "sid"); + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + convertedHbmFilterDef.name.ShouldEqual(filterDefinitionMapping.Name); + } + + [Test] + public void ShouldConvertNameIfNotPopulated() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + // Don't set anything on the original mapping + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + convertedHbmFilterDef.name.ShouldEqual(filterDefinitionMapping.Name); + } + + [Test] + public void ShouldConvertConditionIfPopulated() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + filterDefinitionMapping.Set(fluent => fluent.Condition, Layer.Conventions, "1=1"); + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + convertedHbmFilterDef.condition.ShouldEqual(filterDefinitionMapping.Condition); + } + + [Test] + public void ShouldNotConvertConditionIfNotPopulated() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + // Don't set anything on the original mapping + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + var blankHbmFilterDef = new HbmFilterDef(); + convertedHbmFilterDef.condition.ShouldEqual(blankHbmFilterDef.condition); + } + + [Test] + public void ShouldNotConvertConditionIfEmpty() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + filterDefinitionMapping.Set(fluent => fluent.Condition, Layer.Conventions, ""); + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + var blankHbmFilterDef = new HbmFilterDef(); + convertedHbmFilterDef.condition.ShouldEqual(blankHbmFilterDef.condition); + } + + [Test] + public void ShouldConvertParameters() + { + IDictionary parameters = new Dictionary(); + parameters.Add(SAMPLE_FILTER_PARAM_1); + parameters.Add(SAMPLE_FILTER_PARAM_2); + + var filterDefinitionMapping = new FilterDefinitionMapping(); + foreach (var parameter in parameters) + filterDefinitionMapping.Parameters.Add(parameter); + + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + + // Since we check the actual conversion of FilterDefinitionMapping parameters to HbmFilterParam elsewhere, + // and dictionaries have no order but arrays do (which complicates trying to test value equality), just check + // that we got the right number of items, here. + convertedHbmFilterDef.Items.ShouldNotBeNull(); + convertedHbmFilterDef.Items.Length.ShouldEqual(parameters.Count); + } + + [Test] + public void ShouldNotConvertZeroParameters() + { + var filterDefinitionMapping = new FilterDefinitionMapping(); + // Don't add any parameters + var convertedHbmFilterDef = converter.Convert(filterDefinitionMapping); + var blankHbmFilterDef = new HbmFilterDef(); + convertedHbmFilterDef.Items.ShouldEqual(blankHbmFilterDef.Items); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmGeneratorConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmGeneratorConverterTester.cs new file mode 100644 index 000000000..e615a4353 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmGeneratorConverterTester.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmGeneratorConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertConditionIfPopulated() + { + var generatorMapping = new GeneratorMapping(); + generatorMapping.Set(fluent => fluent.Class, Layer.Conventions, "class"); + var convertedHbmGenerator = converter.Convert(generatorMapping); + convertedHbmGenerator.@class.ShouldEqual(generatorMapping.Class); + } + + [Test] + public void ShouldNotConvertConditionIfNotPopulated() + { + var generatorMapping = new GeneratorMapping(); + // Don't set anything on the original mapping + var convertedHbmGenerator = converter.Convert(generatorMapping); + var blankHbmGenerator = new HbmGenerator(); + convertedHbmGenerator.@class.ShouldEqual(blankHbmGenerator.@class); + } + + [Test] + public void ShouldNotConvertConditionIfEmpty() + { + var generatorMapping = new GeneratorMapping(); + generatorMapping.Set(fluent => fluent.Class, Layer.Conventions, ""); + var convertedHbmGenerator = converter.Convert(generatorMapping); + var blankHbmGenerator = new HbmGenerator(); + convertedHbmGenerator.@class.ShouldEqual(blankHbmGenerator.@class); + } + + [Test] + public void ShouldConvertParameters() + { + var parameters = new Dictionary(); + parameters.Add("first", "value"); + parameters.Add("second", "another-value"); + + var generatorMapping = new GeneratorMapping(); + foreach (var parameter in parameters) + generatorMapping.Params.Add(parameter); + + var convertedHbmGenerator = converter.Convert(generatorMapping); + + // Since we check the actual conversion of GeneratorMapping parameters to HbmFilterParam elsewhere, + // and dictionaries have no order but arrays do (which complicates trying to test value equality), just check + // that we got the right number of items, here. + convertedHbmGenerator.param.ShouldNotBeNull(); + convertedHbmGenerator.param.Length.ShouldEqual(parameters.Count); + } + + [Test] + public void ShouldNotConvertZeroParameters() + { + var generatorMapping = new GeneratorMapping(); + // Don't add any parameters + var convertedHbmGenerator = converter.Convert(generatorMapping); + var blankHbmGenerator = new HbmGenerator(); + convertedHbmGenerator.param.ShouldEqual(blankHbmGenerator.param); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmHibernateMappingConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmHibernateMappingConverterTester.cs new file mode 100644 index 000000000..173546e95 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmHibernateMappingConverterTester.cs @@ -0,0 +1,201 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmHibernateMappingConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.schema.ShouldEqual(hibernateMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.schema.ShouldEqual(blankHbmMapping.schema); + } + + [Test] + public void ShouldConvertDefaultCascadeIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.DefaultCascade, Layer.Conventions, "cas"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.defaultcascade.ShouldEqual(hibernateMapping.DefaultCascade); + } + + [Test] + public void ShouldNotConvertDefaultCascadeIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.defaultcascade.ShouldEqual(blankHbmMapping.defaultcascade); + } + + [Test] + public void ShouldConvertDefaultAccessIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.DefaultAccess, Layer.Conventions, "acc"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.defaultaccess.ShouldEqual(hibernateMapping.DefaultAccess); + } + + [Test] + public void ShouldNotConvertDefaultAccessIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.defaultaccess.ShouldEqual(blankHbmMapping.defaultaccess); + } + + [Test] + public void ShouldConvertAutoImportIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.AutoImport, Layer.Conventions, false); // Defaults to true, so specify false in order to ensure that we can tell if it was set + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.autoimport.ShouldEqual(hibernateMapping.AutoImport); + } + + [Test] + public void ShouldNotConvertAutoImportIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.autoimport.ShouldEqual(blankHbmMapping.autoimport); + } + + [Test] + public void ShouldConvertDefaultLazyIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.DefaultLazy, Layer.Conventions, false); // Defaults to true, so specify false in order to ensure that we can tell if it was set + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.defaultlazy.ShouldEqual(hibernateMapping.DefaultLazy); + } + + [Test] + public void ShouldNotConvertDefaultLazyIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.defaultlazy.ShouldEqual(blankHbmMapping.defaultlazy); + } + + [Test] + public void ShouldConvertCatalogIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.Catalog, Layer.Conventions, "catalog"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.catalog.ShouldEqual(hibernateMapping.Catalog); + } + + [Test] + public void ShouldNotConvertCatalogIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.catalog.ShouldEqual(blankHbmMapping.catalog); + } + + [Test] + public void ShouldConvertNamespaceIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.Namespace, Layer.Conventions, "namespace"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.@namespace.ShouldEqual(hibernateMapping.Namespace); + } + + [Test] + public void ShouldNotConvertNamespaceIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.@namespace.ShouldEqual(blankHbmMapping.@namespace); + } + + [Test] + public void ShouldConvertAssemblyIfPopulated() + { + var hibernateMapping = new HibernateMapping(); + hibernateMapping.Set(fluent => fluent.Assembly, Layer.Conventions, "assembly"); + var convertedHbmMapping = converter.Convert(hibernateMapping); + convertedHbmMapping.assembly.ShouldEqual(hibernateMapping.Assembly); + } + + [Test] + public void ShouldNotConvertAssemblyIfNotPopulated() + { + var hibernateMapping = new HibernateMapping(); + // Don't set anything on the original mapping + var convertedHbmMapping = converter.Convert(hibernateMapping); + var blankHbmMapping = new HbmMapping(); + convertedHbmMapping.assembly.ShouldEqual(blankHbmMapping.assembly); + } + + [Test] + public void ShouldConvertImports() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (hibernateMapping, importMapping) => hibernateMapping.AddImport(importMapping), + hbmMapping => hbmMapping.import); + } + + // NOTE: This test implicitly checks that only one class is converted, as long as only one class is added to the original mapping + [Test] + public void ShouldConvertClasses() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (hibernateMapping, classMapping) => hibernateMapping.AddClass(classMapping), + hbmMapping => hbmMapping.Items); + } + + [Test] + public void ShouldConvertFilterDefs() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (hibernateMapping, filterDefinitionMapping) => hibernateMapping.AddFilter(filterDefinitionMapping), + hbmMapping => hbmMapping.filterdef); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdConverterTester.cs new file mode 100644 index 000000000..dd9f225af --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdConverterTester.cs @@ -0,0 +1,114 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmIdConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var idMapping = new IdMapping(); + idMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmId = converter.Convert(idMapping); + convertedHbmId.access.ShouldEqual(idMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var idMapping = new IdMapping(); + // Don't set anything on the original mapping + var convertedHbmId = converter.Convert(idMapping); + var blankHbmId = new HbmId(); + convertedHbmId.access.ShouldEqual(blankHbmId.access); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var idMapping = new IdMapping(); + idMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmId = converter.Convert(idMapping); + convertedHbmId.name.ShouldEqual(idMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var idMapping = new IdMapping(); + // Don't set anything on the original mapping + var convertedHbmId = converter.Convert(idMapping); + var blankHbmId = new HbmId(); + convertedHbmId.name.ShouldEqual(blankHbmId.name); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var idMapping = new IdMapping(); + idMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference(typeof(HbmIdConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmId = converter.Convert(idMapping); + convertedHbmId.type1.ShouldEqual(idMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var idMapping = new IdMapping(); + // Don't set anything on the original mapping + var convertedHbmId = converter.Convert(idMapping); + var blankHbmId = new HbmId(); + convertedHbmId.type1.ShouldEqual(blankHbmId.type1); + } + + [Test] + public void ShouldConvertUnsavedValueIfPopulated() + { + var idMapping = new IdMapping(); + idMapping.Set(fluent => fluent.UnsavedValue, Layer.Conventions, "u-value"); + var convertedHbmId = converter.Convert(idMapping); + convertedHbmId.unsavedvalue.ShouldEqual(idMapping.UnsavedValue); + } + + [Test] + public void ShouldNotConvertUnsavedValueIfNotPopulated() + { + var idMapping = new IdMapping(); + // Don't set anything on the original mapping + var convertedHbmId = converter.Convert(idMapping); + var blankHbmId = new HbmId(); + convertedHbmId.unsavedvalue.ShouldEqual(blankHbmId.unsavedvalue); + } + + [Test] + public void ShouldConvertGenerator() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (idMapping, generatorMapping) => idMapping.Set(fluent => fluent.Generator, Layer.Defaults, generatorMapping), + hbmId => hbmId.generator); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (idMapping, columnMapping) => idMapping.AddColumn(Layer.Defaults, columnMapping), + hbmId => hbmId.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdentityBasedConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdentityBasedConverterTester.cs new file mode 100644 index 000000000..99b4bd612 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIdentityBasedConverterTester.cs @@ -0,0 +1,33 @@ +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmIdentityBasedConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertIdForIdMapping() + { + ShouldConvertSpecificHbmForMappingChild(); + } + + [Test] + public void ShouldConvertCompositeIdForCompositeIdMapping() + { + ShouldConvertSpecificHbmForMappingChild(); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmImportConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmImportConverterTester.cs new file mode 100644 index 000000000..eb15afe00 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmImportConverterTester.cs @@ -0,0 +1,58 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmImportConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var importMapping = new ImportMapping(); + importMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference(typeof(HbmImportConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmImport = converter.Convert(importMapping); + convertedHbmImport.@class.ShouldEqual(importMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var importMapping = new ImportMapping(); + // Don't set anything on the original mapping + var convertedHbmImport = converter.Convert(importMapping); + var blankHbmImport = new HbmImport(); + convertedHbmImport.@class.ShouldEqual(blankHbmImport.@class); + } + + [Test] + public void ShouldConvertRenameIfPopulated() + { + var importMapping = new ImportMapping(); + importMapping.Set(fluent => fluent.Rename, Layer.Conventions, "renamed"); + var convertedHbmImport = converter.Convert(importMapping); + convertedHbmImport.rename.ShouldEqual(importMapping.Rename); + } + + [Test] + public void ShouldNotConvertRenameIfNotPopulated() + { + var importMapping = new ImportMapping(); + // Don't set anything on the original mapping + var convertedHbmImport = converter.Convert(importMapping); + var blankHbmImport = new HbmImport(); + convertedHbmImport.rename.ShouldEqual(blankHbmImport.rename); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexBasedConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexBasedConverterTester.cs new file mode 100644 index 000000000..eb4ff089d --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexBasedConverterTester.cs @@ -0,0 +1,48 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmIndexBasedConverterTester + { + [Test] + public void ShouldConvertIndexForIndexMappingWithNoOffset() + { + ShouldConvertSpecificHbmForMapping( + () => NewIndexMappingWithNoOffset() + ); + } + + private static IndexMapping NewIndexMappingWithNoOffset() + { + var indexMapping = new IndexMapping(); + // Don't apply a value to IndexMapping.Offset + return indexMapping; + } + + [Test] + public void ShouldConvertListIndexForIndexMappingWithOffset() + { + ShouldConvertSpecificHbmForMapping( + () => NewIndexMappingWithOffset() + ); + } + + private static IndexMapping NewIndexMappingWithOffset() + { + var indexMapping = new IndexMapping(); + indexMapping.Set(fluent => fluent.Offset, Layer.Conventions, 31); + return indexMapping; + } + + [Test] + public void ShouldConvertIndexManyToManyForIndexManyToManyMapping() + { + ShouldConvertSpecificHbmForMappingChild(); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexConverterTester.cs new file mode 100644 index 000000000..e11b87aaa --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexConverterTester.cs @@ -0,0 +1,49 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmIndexConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var indexMapping = new IndexMapping(); + indexMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference("type")); + var convertedHbmIndex = converter.Convert(indexMapping); + convertedHbmIndex.type.ShouldEqual(indexMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var indexMapping = new IndexMapping(); + // Don't set anything on the original mapping + var convertedHbmIndex = converter.Convert(indexMapping); + var blankHbmIndex = new HbmIndex(); + convertedHbmIndex.type.ShouldEqual(blankHbmIndex.type); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (indexMapping, columnMapping) => indexMapping.AddColumn(Layer.Defaults, columnMapping), + hbmIndex => hbmIndex.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexManyToManyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexManyToManyConverterTester.cs new file mode 100644 index 000000000..93c25498b --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmIndexManyToManyConverterTester.cs @@ -0,0 +1,87 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmIndexManyToManyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + indexManyToManyMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("cls")); + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + convertedHbmIndexManyToMany.@class.ShouldEqual(indexManyToManyMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + var blankHbmIndexManyToMany = new HbmIndexManyToMany(); + convertedHbmIndexManyToMany.@class.ShouldEqual(blankHbmIndexManyToMany.@class); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + indexManyToManyMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "FKTest"); + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + convertedHbmIndexManyToMany.foreignkey.ShouldEqual(indexManyToManyMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + var blankHbmIndexManyToMany = new HbmIndexManyToMany(); + convertedHbmIndexManyToMany.foreignkey.ShouldEqual(blankHbmIndexManyToMany.foreignkey); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + indexManyToManyMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + convertedHbmIndexManyToMany.entityname.ShouldEqual(indexManyToManyMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var indexManyToManyMapping = new IndexManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmIndexManyToMany = converter.Convert(indexManyToManyMapping); + var blankHbmIndexManyToMany = new HbmIndexManyToMany(); + convertedHbmIndexManyToMany.entityname.ShouldEqual(blankHbmIndexManyToMany.entityname); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (indexManyToManyMapping, columnMapping) => indexManyToManyMapping.AddColumn(Layer.Defaults, columnMapping), + hbmIndexManyToMany => hbmIndexManyToMany.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinConverterTester.cs new file mode 100644 index 000000000..615449dea --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinConverterTester.cs @@ -0,0 +1,340 @@ +using System; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmJoinConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Value field tests + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.table.ShouldEqual(joinMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.table.ShouldEqual(blankHbmJoin.table); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.schema.ShouldEqual(joinMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.schema.ShouldEqual(blankHbmJoin.schema); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmJoinFetch.Select; // Defaults to Join, so use this to ensure that we can detect changes + + var joinMapping = new JoinMapping(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + joinMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.fetch.ShouldEqual(fetch); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(joinMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.fetch.ShouldEqual(blankHbmJoin.fetch); + } + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this in order to tell if it actually changed + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.inverse.ShouldEqual(joinMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.inverse.ShouldEqual(blankHbmJoin.inverse); + } + + [Test] + public void ShouldConvertOptionalIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Optional, Layer.Conventions, true); // Defaults to false, so use this in order to tell if it actually changed + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.optional.ShouldEqual(joinMapping.Optional); + } + + [Test] + public void ShouldNotConvertOptionalIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.optional.ShouldEqual(blankHbmJoin.optional); + } + + [Test] + public void ShouldConvertCatalogIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Catalog, Layer.Conventions, "catalog"); + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.catalog.ShouldEqual(joinMapping.Catalog); + } + + [Test] + public void ShouldNotConvertCatalogIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.catalog.ShouldEqual(blankHbmJoin.catalog); + } + + #endregion Value field tests + + #region Non-converter-based subobject tests + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var joinMapping = new JoinMapping(); + joinMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmJoin = converter.Convert(joinMapping); + convertedHbmJoin.subselect.Text.ShouldEqual(new string[] { joinMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var joinMapping = new JoinMapping(); + // Don't set anything on the original mapping + var convertedHbmJoin = converter.Convert(joinMapping); + var blankHbmJoin = new HbmJoin(); + convertedHbmJoin.subselect.ShouldEqual(blankHbmJoin.subselect); + } + + #endregion Non-converter-based subobject tests + + #region Converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (joinMapping, keyMapping) => joinMapping.Set(fluent => fluent.Key, Layer.Conventions, keyMapping), + hbmJoin => hbmJoin.key); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (joinMapping, propertyMapping) => joinMapping.AddProperty(propertyMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (joinMapping, manyToOneMapping) => joinMapping.AddReference(manyToOneMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.Component), + (joinMapping, componentMapping) => joinMapping.AddComponent(componentMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new ComponentMapping(ComponentType.DynamicComponent), + (joinMapping, componentMapping) => joinMapping.AddComponent(componentMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (joinMapping, anyMapping) => joinMapping.AddAny(anyMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Map(), + (joinMapping, mapMapping) => joinMapping.AddCollection(mapMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Set(), + (joinMapping, setMapping) => joinMapping.AddCollection(setMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.List(), + (joinMapping, listMapping) => joinMapping.AddCollection(listMapping), + hbmJoin => hbmJoin.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Bag(), + (joinMapping, bagMapping) => joinMapping.AddCollection(bagMapping), + hbmJoin => hbmJoin.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => CollectionMapping.Array(), + (joinMapping, bagMapping) => joinMapping.AddCollection(bagMapping), + hbmJoin => hbmJoin.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlInsert() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-insert", ""), + (joinMapping, storedProcedureMapping) => joinMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoin => hbmJoin.sqlinsert); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlUpdate() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-update", ""), + (joinMapping, storedProcedureMapping) => joinMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoin => hbmJoin.sqlupdate); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlDelete() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new StoredProcedureMapping("sql-delete", ""), + (joinMapping, storedProcedureMapping) => joinMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoin => hbmJoin.sqldelete); + } + + [Test] + public void ShouldConvertStoredProcedure_Unsupported() + { + var unsupportedSPType = "invalid"; + + // Set up a fake converter + var fakeConverter = A.Fake>(); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so that it will use the fake implementation) + var container = new HbmConverterContainer(); + container.Register>(cnvrt => fakeConverter); + converter = container.Resolve>(); + + // Allocate the join mapping and a stored procedure submapping with an unsupported sptype + var joinMapping = new JoinMapping(); + joinMapping.AddStoredProcedure(new StoredProcedureMapping(unsupportedSPType, "")); + + // This should throw + Assert.Throws(() => converter.Convert(joinMapping)); + + // We don't care if it made a call to the subobject conversion logic or not (it is low enough cost that it doesn't + // really matter in the case of failure, and some implementation approaches that uses this may be simpler). + } + + #endregion Converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinedSubclassConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinedSubclassConverterTester.cs new file mode 100644 index 000000000..ba31c36f6 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmJoinedSubclassConverterTester.cs @@ -0,0 +1,546 @@ +using System; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmJoinedSubclassConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Value field tests + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.table.ShouldEqual(subclassMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.table.ShouldEqual(blankHbmJoinedSubclass.table); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.schema.ShouldEqual(subclassMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.schema.ShouldEqual(blankHbmJoinedSubclass.schema); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.check.ShouldEqual(subclassMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.check.ShouldEqual(blankHbmJoinedSubclass.check); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(HbmJoinedSubclassConverterTester))); // Not really representative, but the class is guaranteed to exist + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.persister.ShouldEqual(subclassMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.persister.ShouldEqual(blankHbmJoinedSubclass.persister); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.name.ShouldEqual(subclassMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.name.ShouldEqual(blankHbmJoinedSubclass.name); + } + + [Test] + public void ShouldConvertProxyIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Proxy, Layer.Conventions, "p"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.proxy.ShouldEqual(subclassMapping.Proxy); + } + + [Test] + public void ShouldNotConvertProxyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.proxy.ShouldEqual(blankHbmJoinedSubclass.proxy); + } + + [Test] + public void ShouldConvertLazyIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmJoinedSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, false); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmJoinedSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.lazy.ShouldEqual(blankHbmJoinedSubclass.lazy); + Assert.That(convertedHbmJoinedSubclass.lazySpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertDynamicUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.DynamicUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.dynamicupdate.ShouldEqual(subclassMapping.DynamicUpdate); + } + + [Test] + public void ShouldNotConvertDynamicUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.dynamicupdate.ShouldEqual(blankHbmJoinedSubclass.dynamicupdate); + } + + [Test] + public void ShouldConvertDynamicInsertIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.DynamicInsert, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.dynamicinsert.ShouldEqual(subclassMapping.DynamicInsert); + } + + [Test] + public void ShouldNotConvertDynamicInsertIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.dynamicinsert.ShouldEqual(blankHbmJoinedSubclass.dynamicinsert); + } + + [Test] + public void ShouldConvertSelectBeforeUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.SelectBeforeUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.selectbeforeupdate.ShouldEqual(subclassMapping.SelectBeforeUpdate); + } + + [Test] + public void ShouldNotConvertSelectBeforeUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.selectbeforeupdate.ShouldEqual(blankHbmJoinedSubclass.selectbeforeupdate); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, true); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmJoinedSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, false); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmJoinedSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldNotConvertAbstractIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.@abstract.ShouldEqual(blankHbmJoinedSubclass.@abstract); + Assert.That(convertedHbmJoinedSubclass.abstractSpecified.Equals(false), "Abstract was marked as specified"); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "entity1"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.entityname.ShouldEqual(subclassMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.entityname.ShouldEqual(blankHbmJoinedSubclass.entityname); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.batchsize.ShouldEqual(subclassMapping.BatchSize.ToString()); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.batchsize.ShouldEqual(blankHbmJoinedSubclass.batchsize); + } + + #endregion Value field tests + + #region Non-converter-based subobject tests + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + convertedHbmJoinedSubclass.subselect.Text.ShouldEqual(new string[] { subclassMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + // Don't set anything on the original mapping + var convertedHbmJoinedSubclass = converter.Convert(subclassMapping); + var blankHbmJoinedSubclass = new HbmJoinedSubclass(); + convertedHbmJoinedSubclass.subselect.ShouldEqual(blankHbmJoinedSubclass.subselect); + } + + #endregion Non-converter-based subobject tests + + #region Converter-based subobject tests + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, propertyMapping) => subclassMapping.AddProperty(propertyMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, manyToOneMapping) => subclassMapping.AddReference(manyToOneMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, oneToOneMapping) => subclassMapping.AddOneToOne(oneToOneMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new ComponentMapping(ComponentType.Component), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new ComponentMapping(ComponentType.DynamicComponent), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, anyMapping) => subclassMapping.AddAny(anyMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => CollectionMapping.Map(), + (subclassMapping, mapMapping) => subclassMapping.AddCollection(mapMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => CollectionMapping.Set(), + (subclassMapping, setMapping) => subclassMapping.AddCollection(setMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => CollectionMapping.List(), + (subclassMapping, listMapping) => subclassMapping.AddCollection(listMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => CollectionMapping.Bag(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => CollectionMapping.Array(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmJoinedSubclass => hbmJoinedSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertSubclasses_Subclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new SubclassMapping(SubclassType.Subclass), + (joinedSubclassMapping, subclassMapping) => joinedSubclassMapping.AddSubclass(subclassMapping), + hbmJoinedSubclass => hbmJoinedSubclass.joinedsubclass1) + ); + } + + [Test] + public void ShouldConvertSubclasses_JoinedSubclass() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new SubclassMapping(SubclassType.JoinedSubclass), + (joinedSubclassMapping1, joinedSubclassMapping2) => joinedSubclassMapping1.AddSubclass(joinedSubclassMapping2), + hbmJoinedSubclass => hbmJoinedSubclass.joinedsubclass1); + } + + [Test] + public void ShouldConvertSubclasses_UnionSubclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new SubclassMapping(SubclassType.UnionSubclass), + (joinedSubclassMapping, unionSubclassMapping) => joinedSubclassMapping.AddSubclass(unionSubclassMapping), + hbmJoinedSubclass => hbmJoinedSubclass.joinedsubclass1) + ); + } + + [Test] + public void ShouldConvertKeys() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.JoinedSubclass), + (subclassMapping, keyMapping) => subclassMapping.Set(fluent => fluent.Key, Layer.Conventions, keyMapping), + hbmJoinedSubclass => hbmJoinedSubclass.key); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlInsert() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new StoredProcedureMapping("sql-insert", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoinedSubclass => hbmJoinedSubclass.sqlinsert); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlUpdate() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new StoredProcedureMapping("sql-update", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoinedSubclass => hbmJoinedSubclass.sqlupdate); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlDelete() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.JoinedSubclass), + () => new StoredProcedureMapping("sql-delete", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmJoinedSubclass => hbmJoinedSubclass.sqldelete); + } + + [Test] + public void ShouldConvertStoredProcedure_Unsupported() + { + var unsupportedSPType = "invalid"; + + // Set up a fake converter + var fakeConverter = A.Fake>(); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and FMain == FSub + HMain == HSub (e.g., subclasses-of-subclasses) we + // get the real converter for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate the subclass mapping and a stored procedure submapping with an unsupported sptype + var subclassMapping = new SubclassMapping(SubclassType.JoinedSubclass); + subclassMapping.AddStoredProcedure(new StoredProcedureMapping(unsupportedSPType, "")); + + // This should throw + Assert.Throws(() => converter.Convert(subclassMapping)); + + // We don't care if it made a call to the subobject conversion logic or not (it is low enough cost that it doesn't + // really matter in the case of failure, and some implementation approaches that uses this may be simpler). + } + + #endregion Converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyConverterTester.cs new file mode 100644 index 000000000..c0c3be29d --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyConverterTester.cs @@ -0,0 +1,162 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmKeyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "fk"); + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.foreignkey.ShouldEqual(keyMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.foreignkey.ShouldEqual(blankHbmKey.foreignkey); + } + + [Test] + public void ShouldConvertPropertyRefIfPopulated() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.PropertyRef, Layer.Conventions, "prop"); + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.propertyref.ShouldEqual(keyMapping.PropertyRef); + } + + [Test] + public void ShouldNotConvertPropertyRefIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.propertyref.ShouldEqual(blankHbmKey.propertyref); + } + + [Test] + public void ShouldConvertOnDeleteIfPopulatedWithValidValue() + { + var ondelete = HbmOndelete.Cascade; // Defaults to Noaction, so use this to ensure that we can detect changes + + var keyMapping = new KeyMapping(); + var ondeleteDict = new XmlLinkedEnumBiDictionary(); + keyMapping.Set(fluent => fluent.OnDelete, Layer.Conventions, ondeleteDict[ondelete]); + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.ondelete.ShouldEqual(ondelete); + } + + [Test] + public void ShouldFailToConvertOnDeleteIfPopulatedWithInvalidValue() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.OnDelete, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(keyMapping)); + } + + [Test] + public void ShouldNotConvertOnDeleteIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.ondelete.ShouldEqual(blankHbmKey.ondelete); + } + + [Test] + public void ShouldConvertNotNullIfPopulated() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.NotNull, Layer.Conventions, true); // Defaults to false, so use true so that we can detect changes + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.notnull.ShouldEqual(keyMapping.NotNull); + Assert.That(convertedHbmKey.notnullSpecified.Equals(true), "NotNull was not marked as specified"); + } + + [Test] + public void ShouldNotConvertNotNullIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.notnull.ShouldEqual(blankHbmKey.notnull); + Assert.That(convertedHbmKey.notnullSpecified.Equals(false), "NotNull was marked as specified"); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.Update, Layer.Conventions, true); // Defaults to false, so use true so that we can detect changes + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.update.ShouldEqual(keyMapping.Update); + Assert.That(convertedHbmKey.updateSpecified.Equals(true), "Update was not marked as specified"); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.update.ShouldEqual(blankHbmKey.update); + Assert.That(convertedHbmKey.updateSpecified.Equals(false), "Update was marked as specified"); + } + + [Test] + public void ShouldConvertUniqueIfPopulated() + { + var keyMapping = new KeyMapping(); + keyMapping.Set(fluent => fluent.Unique, Layer.Conventions, true); // Defaults to false, so use true so that we can detect changes + var convertedHbmKey = converter.Convert(keyMapping); + convertedHbmKey.unique.ShouldEqual(keyMapping.Unique); + Assert.That(convertedHbmKey.uniqueSpecified.Equals(true), "Unique was not marked as specified"); + } + + [Test] + public void ShouldNotConvertUniqueIfNotPopulated() + { + var keyMapping = new KeyMapping(); + // Don't set anything on the original mapping + var convertedHbmKey = converter.Convert(keyMapping); + var blankHbmKey = new HbmKey(); + convertedHbmKey.unique.ShouldEqual(blankHbmKey.unique); + Assert.That(convertedHbmKey.uniqueSpecified.Equals(false), "Unique was marked as specified"); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (keyMapping, columnMapping) => keyMapping.AddColumn(Layer.Defaults, columnMapping), + hbmKey => hbmKey.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyManyToOneConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyManyToOneConverterTester.cs new file mode 100644 index 000000000..1c8820619 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyManyToOneConverterTester.cs @@ -0,0 +1,193 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmKeyManyToOneConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.access.ShouldEqual(keyManyToOneMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.access.ShouldEqual(blankHbmKeyManyToOne.access); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.name.ShouldEqual(keyManyToOneMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.name.ShouldEqual(blankHbmKeyManyToOne.name); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference(typeof(HbmKeyManyToOneConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.@class.ShouldEqual(keyManyToOneMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.@class.ShouldEqual(blankHbmKeyManyToOne.@class); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "fk"); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.foreignkey.ShouldEqual(keyManyToOneMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.foreignkey.ShouldEqual(blankHbmKeyManyToOne.foreignkey); + } + + [Test] + public void ShouldConvertLazyIfPopulated_True() + { + var lazyBool = true; + var lazyEnum = HbmRestrictedLaziness.Proxy; // true maps to proxy, false maps to False + + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyBool); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.lazy.ShouldEqual(lazyEnum); + Assert.That(convertedHbmKeyManyToOne.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated_False() + { + var lazyBool = false; + var lazyEnum = HbmRestrictedLaziness.False; // true maps to proxy, false maps to False + + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyBool); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.lazy.ShouldEqual(lazyEnum); + Assert.That(convertedHbmKeyManyToOne.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.lazy.ShouldEqual(blankHbmKeyManyToOne.lazy); + Assert.That(convertedHbmKeyManyToOne.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNotFoundIfPopulatedWithValidValue() + { + var notFound = HbmNotFoundMode.Ignore; // Defaults to Exception, so use this to ensure that we can detect changes + + var keyManyToOneMapping = new KeyManyToOneMapping(); + var notFoundDict = new XmlLinkedEnumBiDictionary(); + keyManyToOneMapping.Set(fluent => fluent.NotFound, Layer.Conventions, notFoundDict[notFound]); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.notfound.ShouldEqual(notFound); + } + + [Test] + public void ShouldFailToConvertNotFoundIfPopulatedWithInvalidValue() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.NotFound, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(keyManyToOneMapping)); + } + + [Test] + public void ShouldNotConvertNotFoundIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.notfound.ShouldEqual(blankHbmKeyManyToOne.notfound); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + keyManyToOneMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + convertedHbmKeyManyToOne.entityname.ShouldEqual(keyManyToOneMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var keyManyToOneMapping = new KeyManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyManyToOne = converter.Convert(keyManyToOneMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmKeyManyToOne.entityname.ShouldEqual(blankHbmKeyManyToOne.entityname); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (keyManyToOneMapping, columnMapping) => keyManyToOneMapping.AddColumn(columnMapping), + hbmKeyManyToOne => hbmKeyManyToOne.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyPropertyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyPropertyConverterTester.cs new file mode 100644 index 000000000..a0fae6660 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmKeyPropertyConverterTester.cs @@ -0,0 +1,138 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmKeyPropertyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + keyPropertyMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + convertedHbmKeyProperty.access.ShouldEqual(keyPropertyMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + var blankHbmKeyProperty = new HbmKeyProperty(); + convertedHbmKeyProperty.access.ShouldEqual(blankHbmKeyProperty.access); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + keyPropertyMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + convertedHbmKeyProperty.name.ShouldEqual(keyPropertyMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + var blankHbmKeyProperty = new HbmKeyProperty(); + convertedHbmKeyProperty.name.ShouldEqual(blankHbmKeyProperty.name); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + keyPropertyMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference(typeof(HbmKeyPropertyConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + convertedHbmKeyProperty.type1.ShouldEqual(keyPropertyMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + var blankHbmKeyProperty = new HbmKeyProperty(); + convertedHbmKeyProperty.type1.ShouldEqual(blankHbmKeyProperty.type1); + } + + // If the length attribute is set, but no columns are present, convert it normally + [Test] + public void ShouldConvertLengthIfPopulatedWithoutColumns() + { + var keyPropertyMapping = new KeyPropertyMapping(); + keyPropertyMapping.Set(fluent => fluent.Length, Layer.Conventions, 8); + // Don't add any columns + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + convertedHbmKeyProperty.length.ShouldEqual(keyPropertyMapping.Length.ToString()); + } + + [Test] + public void ShouldNotConvertLengthIfPopulatedWithColumns() + { + var keyPropertyMappingLength = 8; + var columnMappingLength = -1; + + // Set up the key property with a length and a mix of columns that do/don't have their own length + var keyPropertyMapping = new KeyPropertyMapping(); + keyPropertyMapping.Set(fluent => fluent.Length, Layer.Conventions, keyPropertyMappingLength); + var columnMappingWithLength = new ColumnMapping(); + columnMappingWithLength.Set(fluent => fluent.Length, Layer.Conventions, columnMappingLength); + keyPropertyMapping.AddColumn(columnMappingWithLength); + var columnMappingWithoutLength = new ColumnMapping(); + keyPropertyMapping.AddColumn(columnMappingWithoutLength); + + // Run the converter + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + + // Check that the Length value wasn't propagated to the HbmKeyProperty + var blankHbmKeyProperty = new HbmKeyProperty(); + convertedHbmKeyProperty.length.ShouldEqual(blankHbmKeyProperty.length); + + // Check that the length property _was_ propagated to the columns, but only those which did not already have a length value + // NOTE: This covers Bug #231 (which has a separate test in the XML variant) + columnMappingWithLength.Length.ShouldEqual(columnMappingLength); + columnMappingWithoutLength.Length.ShouldEqual(keyPropertyMappingLength); + } + + // If the length attribute is not set, do not convert it + [Test] + public void ShouldNotConvertLengthIfNotPopulated() + { + var keyPropertyMapping = new KeyPropertyMapping(); + // Don't set anything on the original mapping + // Also don't add any columns + var convertedHbmKeyProperty = converter.Convert(keyPropertyMapping); + var blankHbmKeyProperty = new HbmKeyProperty(); + convertedHbmKeyProperty.length.ShouldEqual(blankHbmKeyProperty.length); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (keyPropertyMapping, columnMapping) => keyPropertyMapping.AddColumn(columnMapping), + hbmKeyProperty => hbmKeyProperty.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmListConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmListConverterTester.cs new file mode 100644 index 000000000..4d8d7b094 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmListConverterTester.cs @@ -0,0 +1,485 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmListConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Base collection attribute value field tests + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.access.ShouldEqual(listMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.access.ShouldEqual(blankHbmList.access); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.batchsize.ShouldEqual(listMapping.BatchSize); + Assert.That(convertedHbmList.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.batchsize.ShouldEqual(blankHbmList.batchsize); + Assert.That(convertedHbmList.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.cascade.ShouldEqual(listMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.cascade.ShouldEqual(blankHbmList.cascade); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.check.ShouldEqual(listMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.check.ShouldEqual(blankHbmList.check); + } + + [Test] + public void ShouldConvertCollectionTypeIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, new TypeReference("type")); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.collectiontype.ShouldEqual(listMapping.CollectionType.ToString()); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfEmpty() + { + var listMapping = CollectionMapping.List(); + // List an explicitly empty type reference + listMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, TypeReference.Empty); + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.collectiontype.ShouldEqual(blankHbmList.collectiontype); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.collectiontype.ShouldEqual(blankHbmList.collectiontype); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmCollectionFetchMode.Subselect; // Defaults to Select, so use something else to properly detect that it changes + + var listMapping = CollectionMapping.List(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + listMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmList.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(listMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.fetch.ShouldEqual(blankHbmList.fetch); + Assert.That(convertedHbmList.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_True() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Generic, Layer.Conventions, true); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.generic.ShouldEqual(listMapping.Generic); + Assert.That(convertedHbmList.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_False() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Generic, Layer.Conventions, false); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.generic.ShouldEqual(listMapping.Generic); + Assert.That(convertedHbmList.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldNotConvertGenericIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.generic.ShouldEqual(blankHbmList.generic); + Assert.That(convertedHbmList.genericSpecified.Equals(false), "Generic was marked as specified"); + } + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.inverse.ShouldEqual(listMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.inverse.ShouldEqual(blankHbmList.inverse); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var hbmLazy = HbmCollectionLazy.False; // Defaults to True, so use something else to properly detect that it changes + + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Lazy, Layer.Conventions, HbmCollectionConverter.FluentHbmLazyBiDict[hbmLazy]); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.lazy.ShouldEqual(hbmLazy); + Assert.That(convertedHbmList.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + // Since it is enum-based, Lazy cannot contain any invalid values, so no need to test for that here + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.lazy.ShouldEqual(blankHbmList.lazy); + Assert.That(convertedHbmList.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.name.ShouldEqual(listMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.name.ShouldEqual(blankHbmList.name); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.optimisticlock.ShouldEqual(listMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.optimisticlock.ShouldEqual(blankHbmList.optimisticlock); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(string))); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.persister.ShouldEqual(listMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.persister.ShouldEqual(blankHbmList.persister); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.schema.ShouldEqual(listMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.schema.ShouldEqual(blankHbmList.schema); + } + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.table.ShouldEqual(listMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.table.ShouldEqual(blankHbmList.table); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.where.ShouldEqual(listMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.where.ShouldEqual(blankHbmList.where); + } + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.subselect.Text.ShouldEqual(new string[] { listMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't list anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.subselect.ShouldEqual(blankHbmList.subselect); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var listMapping = CollectionMapping.List(); + listMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmList = converter.Convert(listMapping); + convertedHbmList.mutable.ShouldEqual(listMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var listMapping = CollectionMapping.List(); + // Don't set anything on the original mapping + var convertedHbmList = converter.Convert(listMapping); + var blankHbmList = new HbmList(); + convertedHbmList.mutable.ShouldEqual(blankHbmList.mutable); + } + + #endregion Base collection attribute value field tests + + #region Type-specific collection attribute value field tests + + // No tests for this type + + #endregion Type-specific collection attribute value field tests + + #region Base collection converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.List(), + (listMapping, keyMapping) => listMapping.Set(fluent => fluent.Key, Layer.Defaults, keyMapping), + hbmList => hbmList.key); + } + + [Test] + public void ShouldConvertICollectionRelationship_OneToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.List(), + () => new OneToManyMapping(), + (listMapping, icrMapping) => listMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmList => hbmList.Item1); + } + + [Test] + public void ShouldConvertICollectionRelationship_ManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.List(), + () => new ManyToManyMapping(), + (listMapping, icrMapping) => listMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmList => hbmList.Item1); + } + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.List(), + (listMapping, cacheMapping) => listMapping.Set(fluent => fluent.Cache, Layer.Defaults, cacheMapping), + hbmList => hbmList.cache); + } + + [Test] + public void ShouldConvertCompositeElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.List(), + (listMapping, compositeElementMapping) => listMapping.Set(fluent => fluent.CompositeElement, Layer.Defaults, compositeElementMapping), + hbmList => hbmList.Item1); + } + + [Test] + public void ShouldConvertElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.List(), + (listMapping, elementMapping) => listMapping.Set(fluent => fluent.Element, Layer.Defaults, elementMapping), + hbmList => hbmList.Item1); + } + + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => CollectionMapping.List(), + (listMapping, filterMapping) => listMapping.AddFilter(filterMapping), + hbmList => hbmList.filter); + } + + #endregion Base collection converter-based subobject tests + + #region Type-specific collection converter-based subobject tests + + [Test] + public void ShouldConvertIIndex_Index() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.List(), + () => new IndexMapping(), + (listMapping, indexMapping) => listMapping.Set(fluent => fluent.Index, Layer.Defaults, indexMapping), + hbmList => hbmList.Item); + } + + // No other index type allowed by HbmList has a fluent mapping at this point + + #endregion Type-specific collection converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmListIndexConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmListIndexConverterTester.cs new file mode 100644 index 000000000..3ecc35b14 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmListIndexConverterTester.cs @@ -0,0 +1,41 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmListIndexConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertOffsetIfPopulated() + { + var indexMapping = new IndexMapping(); + indexMapping.Set(fluent => fluent.Offset, Layer.Conventions, 31); + var convertedHbmListIndex = converter.Convert(indexMapping); + convertedHbmListIndex.@base.ShouldEqual(indexMapping.Offset.ToString()); + } + + // Offset is always populated, since it is a precondition of reaching the list index converter + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (indexMapping, columnMapping) => indexMapping.AddColumn(Layer.Conventions, columnMapping), + hbmListIndex => hbmListIndex.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToManyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToManyConverterTester.cs new file mode 100644 index 000000000..fd5693703 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToManyConverterTester.cs @@ -0,0 +1,247 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using FluentNHibernate.Testing.DomainModel; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmManyToManyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("type")); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.@class.ShouldEqual(manyToManyMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.@class.ShouldEqual(blankHbmManyToMany.@class); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmFetchMode.Join; // Defaults to Select, so use this to ensure that we can spot changes + + var manyToManyMapping = new ManyToManyMapping(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + manyToManyMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmManyToMany.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(manyToManyMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.fetch.ShouldEqual(blankHbmManyToMany.fetch); + Assert.That(convertedHbmManyToMany.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "fk"); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.foreignkey.ShouldEqual(manyToManyMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.foreignkey.ShouldEqual(blankHbmManyToMany.foreignkey); + } + + [Test] + public void ShouldConvertLazyIfPopulated_True() + { + var lazyBool = true; + var lazyEnum = HbmRestrictedLaziness.Proxy; // true maps to proxy, false maps to False + + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyBool); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.lazy.ShouldEqual(lazyEnum); + Assert.That(convertedHbmManyToMany.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated_False() + { + var lazyBool = false; + var lazyEnum = HbmRestrictedLaziness.False; // true maps to proxy, false maps to False + + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyBool); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.lazy.ShouldEqual(lazyEnum); + Assert.That(convertedHbmManyToMany.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmKeyManyToOne = new HbmKeyManyToOne(); + convertedHbmManyToMany.lazy.ShouldEqual(blankHbmKeyManyToOne.lazy); + Assert.That(convertedHbmManyToMany.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNotFoundIfPopulatedWithValidValue() + { + var notFound = HbmNotFoundMode.Ignore; // Defaults to Exception, so use this to ensure that we can detect changes + + var manyToManyMapping = new ManyToManyMapping(); + var notFoundDict = new XmlLinkedEnumBiDictionary(); + manyToManyMapping.Set(fluent => fluent.NotFound, Layer.Conventions, notFoundDict[notFound]); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.notfound.ShouldEqual(notFound); + } + + [Test] + public void ShouldFailToConvertNotFoundIfPopulatedWithInvalidValue() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.NotFound, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(manyToManyMapping)); + } + + [Test] + public void ShouldNotConvertNotFoundIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.notfound.ShouldEqual(blankHbmManyToMany.notfound); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.where.ShouldEqual(manyToManyMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.where.ShouldEqual(blankHbmManyToMany.where); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.entityname.ShouldEqual(manyToManyMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.entityname.ShouldEqual(blankHbmManyToMany.entityname); + } + + [Test] + public void ShouldConvertOrderByIfPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.OrderBy, Layer.Conventions, "col1"); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.orderby.ShouldEqual(manyToManyMapping.OrderBy); + } + + [Test] + public void ShouldNotConvertOrderByIfNotPopulated() + { + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.orderby.ShouldEqual(blankHbmManyToMany.orderby); + } + + [Test] + public void ShouldConvertChildPropertyRefIfPopulated() + { + // Actually mapped from ChildPropertyRef -> propertyref + var manyToManyMapping = new ManyToManyMapping(); + manyToManyMapping.Set(fluent => fluent.ChildPropertyRef, Layer.Conventions, "childprop"); + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + convertedHbmManyToMany.propertyref.ShouldEqual(manyToManyMapping.ChildPropertyRef); + } + + [Test] + public void ShouldNotConvertChildPropertyRefIfNotPopulated() + { + // Actually mapped from ChildPropertyRef -> propertyref + var manyToManyMapping = new ManyToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToMany = converter.Convert(manyToManyMapping); + var blankHbmManyToMany = new HbmManyToMany(); + convertedHbmManyToMany.propertyref.ShouldEqual(blankHbmManyToMany.propertyref); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (manyToManyMapping, columnMapping) => manyToManyMapping.AddColumn(Layer.Conventions, columnMapping), + hbmManyToMany => hbmManyToMany.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToOneConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToOneConverterTester.cs new file mode 100644 index 000000000..8c4d05c1a --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmManyToOneConverterTester.cs @@ -0,0 +1,334 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using FluentNHibernate.Testing.DomainModel; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmManyToOneConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.access.ShouldEqual(manyToOneMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.access.ShouldEqual(blankHbmManyToOne.access); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.cascade.ShouldEqual(manyToOneMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.cascade.ShouldEqual(blankHbmManyToOne.cascade); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference(typeof(Record))); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.@class.ShouldEqual(manyToOneMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.@class.ShouldEqual(blankHbmManyToOne.@class); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmFetchMode.Join; // Defaults to Select, so use this to ensure that we can spot changes + + var manyToOneMapping = new ManyToOneMapping(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + manyToOneMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmManyToOne.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(manyToOneMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.fetch.ShouldEqual(blankHbmManyToOne.fetch); + Assert.That(convertedHbmManyToOne.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "fk"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.foreignkey.ShouldEqual(manyToOneMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.foreignkey.ShouldEqual(blankHbmManyToOne.foreignkey); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Insert, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.insert.ShouldEqual(manyToOneMapping.Insert); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.insert.ShouldEqual(blankHbmManyToOne.insert); + } + + [Test] + public void ShouldConvertLazyIfPopulatedWithValidValue() + { + var lazy = HbmLaziness.Proxy; // Defaults to False, so use this to ensure that we can detect changes + + var manyToOneMapping = new ManyToOneMapping(); + var lazyDict = new XmlLinkedEnumBiDictionary(); + manyToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyDict[lazy]); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.lazy.ShouldEqual(lazy); + Assert.That(convertedHbmManyToOne.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertLazyIfPopulatedWithInvalidValue() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(manyToOneMapping)); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.lazy.ShouldEqual(blankHbmManyToOne.lazy); + Assert.That(convertedHbmManyToOne.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Name, Layer.Conventions, "nm"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.name.ShouldEqual(manyToOneMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.name.ShouldEqual(blankHbmManyToOne.name); + } + + [Test] + public void ShouldConvertNotFoundIfPopulatedWithValidValue() + { + var notFound = HbmNotFoundMode.Ignore; // Defaults to Exception, so use this to ensure that we can detect changes + + var manyToOneMapping = new ManyToOneMapping(); + var notFoundDict = new XmlLinkedEnumBiDictionary(); + manyToOneMapping.Set(fluent => fluent.NotFound, Layer.Conventions, notFoundDict[notFound]); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.notfound.ShouldEqual(notFound); + } + + [Test] + public void ShouldFailToConvertNotFoundIfPopulatedWithInvalidValue() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.NotFound, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(manyToOneMapping)); + } + + [Test] + public void ShouldNotConvertNotFoundIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.notfound.ShouldEqual(blankHbmManyToOne.notfound); + } + + [Test] + public void ShouldConvertPropertyRefIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.PropertyRef, Layer.Conventions, "pr"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.propertyref.ShouldEqual(manyToOneMapping.PropertyRef); + } + + [Test] + public void ShouldNotConvertPropertyRefIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.propertyref.ShouldEqual(blankHbmManyToOne.propertyref); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Update, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.update.ShouldEqual(manyToOneMapping.Update); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.update.ShouldEqual(blankHbmManyToOne.update); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.entityname.ShouldEqual(manyToOneMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.entityname.ShouldEqual(blankHbmManyToOne.entityname); + } + + [Test] + public void ShouldConvertFormulaIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.Formula, Layer.Conventions, "form"); + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.formula.ShouldEqual(manyToOneMapping.Formula); + } + + [Test] + public void ShouldNotConvertFormulaIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.formula.ShouldEqual(blankHbmManyToOne.formula); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + manyToOneMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + convertedHbmManyToOne.optimisticlock.ShouldEqual(manyToOneMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var manyToOneMapping = new ManyToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmManyToOne = converter.Convert(manyToOneMapping); + var blankHbmManyToOne = new HbmManyToOne(); + convertedHbmManyToOne.optimisticlock.ShouldEqual(blankHbmManyToOne.optimisticlock); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (manyToOneMapping, columnMapping) => manyToOneMapping.AddColumn(Layer.Conventions, columnMapping), + hbmManyToOne => hbmManyToOne.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmMapConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmMapConverterTester.cs new file mode 100644 index 000000000..0d54dafcf --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmMapConverterTester.cs @@ -0,0 +1,529 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmMapConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Base collection attribute value field tests + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.access.ShouldEqual(mapMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.access.ShouldEqual(blankHbmMap.access); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.batchsize.ShouldEqual(mapMapping.BatchSize); + Assert.That(convertedHbmMap.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.batchsize.ShouldEqual(blankHbmMap.batchsize); + Assert.That(convertedHbmMap.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.cascade.ShouldEqual(mapMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.cascade.ShouldEqual(blankHbmMap.cascade); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.check.ShouldEqual(mapMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.check.ShouldEqual(blankHbmMap.check); + } + + [Test] + public void ShouldConvertCollectionTypeIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, new TypeReference("type")); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.collectiontype.ShouldEqual(mapMapping.CollectionType.ToString()); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfEmpty() + { + var mapMapping = CollectionMapping.Map(); + // Map an explicitly empty type reference + mapMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, TypeReference.Empty); + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.collectiontype.ShouldEqual(blankHbmMap.collectiontype); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.collectiontype.ShouldEqual(blankHbmMap.collectiontype); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmCollectionFetchMode.Subselect; // Defaults to Select, so use something else to properly detect that it changes + + var mapMapping = CollectionMapping.Map(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + mapMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmMap.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(mapMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.fetch.ShouldEqual(blankHbmMap.fetch); + Assert.That(convertedHbmMap.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_True() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Generic, Layer.Conventions, true); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.generic.ShouldEqual(mapMapping.Generic); + Assert.That(convertedHbmMap.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_False() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Generic, Layer.Conventions, false); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.generic.ShouldEqual(mapMapping.Generic); + Assert.That(convertedHbmMap.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldNotConvertGenericIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.generic.ShouldEqual(blankHbmMap.generic); + Assert.That(convertedHbmMap.genericSpecified.Equals(false), "Generic was marked as specified"); + } + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.inverse.ShouldEqual(mapMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.inverse.ShouldEqual(blankHbmMap.inverse); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var hbmLazy = HbmCollectionLazy.False; // Defaults to True, so use something else to properly detect that it changes + + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Lazy, Layer.Conventions, HbmCollectionConverter.FluentHbmLazyBiDict[hbmLazy]); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.lazy.ShouldEqual(hbmLazy); + Assert.That(convertedHbmMap.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + // Since it is enum-based, Lazy cannot contain any invalid values, so no need to test for that here + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.lazy.ShouldEqual(blankHbmMap.lazy); + Assert.That(convertedHbmMap.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.name.ShouldEqual(mapMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.name.ShouldEqual(blankHbmMap.name); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.optimisticlock.ShouldEqual(mapMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.optimisticlock.ShouldEqual(blankHbmMap.optimisticlock); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(string))); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.persister.ShouldEqual(mapMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.persister.ShouldEqual(blankHbmMap.persister); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.schema.ShouldEqual(mapMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.schema.ShouldEqual(blankHbmMap.schema); + } + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.table.ShouldEqual(mapMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.table.ShouldEqual(blankHbmMap.table); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.where.ShouldEqual(mapMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.where.ShouldEqual(blankHbmMap.where); + } + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.subselect.Text.ShouldEqual(new string[] { mapMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.subselect.ShouldEqual(blankHbmMap.subselect); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.mutable.ShouldEqual(mapMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't set anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.mutable.ShouldEqual(blankHbmMap.mutable); + } + + #endregion Base collection attribute value field tests + + #region Type-specific collection attribute value field tests + + [Test] + public void ShouldConvertOrderByIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.OrderBy, Layer.Conventions, "ord"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.orderby.ShouldEqual(mapMapping.OrderBy); + } + + [Test] + public void ShouldNotConvertOrderByIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.orderby.ShouldEqual(blankHbmMap.orderby); + } + + [Test] + public void ShouldConvertSortIfPopulated() + { + var mapMapping = CollectionMapping.Map(); + mapMapping.Set(fluent => fluent.Sort, Layer.Conventions, "asc"); + var convertedHbmMap = converter.Convert(mapMapping); + convertedHbmMap.sort.ShouldEqual(mapMapping.Sort); + } + + [Test] + public void ShouldNotConvertSortIfNotPopulated() + { + var mapMapping = CollectionMapping.Map(); + // Don't map anything on the original mapping + var convertedHbmMap = converter.Convert(mapMapping); + var blankHbmMap = new HbmMap(); + convertedHbmMap.sort.ShouldEqual(blankHbmMap.sort); + } + + #endregion Type-specific collection attribute value field tests + + #region Base collection converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Map(), + (mapMapping, keyMapping) => mapMapping.Set(fluent => fluent.Key, Layer.Defaults, keyMapping), + hbmMap => hbmMap.key); + } + + [Test] + public void ShouldConvertICollectionRelationship_OneToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + () => new OneToManyMapping(), + (mapMapping, icrMapping) => mapMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmMap => hbmMap.Item1); + } + + [Test] + public void ShouldConvertICollectionRelationship_ManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + () => new ManyToManyMapping(), + (mapMapping, icrMapping) => mapMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmMap => hbmMap.Item1); + } + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Map(), + (mapMapping, cacheMapping) => mapMapping.Set(fluent => fluent.Cache, Layer.Defaults, cacheMapping), + hbmMap => hbmMap.cache); + } + + [Test] + public void ShouldConvertCompositeElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + (mapMapping, compositeElementMapping) => mapMapping.Set(fluent => fluent.CompositeElement, Layer.Defaults, compositeElementMapping), + hbmMap => hbmMap.Item1); + } + + [Test] + public void ShouldConvertElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + (mapMapping, elementMapping) => mapMapping.Set(fluent => fluent.Element, Layer.Defaults, elementMapping), + hbmMap => hbmMap.Item1); + } + + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => CollectionMapping.Map(), + (mapMapping, filterMapping) => mapMapping.AddFilter(filterMapping), + hbmMap => hbmMap.filter); + } + + #endregion Base collection converter-based subobject tests + + #region Type-specific collection converter-based subobject tests + + [Test] + public void ShouldConvertIIndex_Index() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + () => new IndexMapping(), + (mapMapping, indexMapping) => mapMapping.Set(fluent => fluent.Index, Layer.Defaults, indexMapping), + hbmMap => hbmMap.Item); + } + + [Test] + public void ShouldConvertIIndex_IndexManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Map(), + () => new IndexManyToManyMapping(), + (mapMapping, indexMapping) => mapMapping.Set(fluent => fluent.Index, Layer.Defaults, indexMapping), + hbmMap => hbmMap.Item); + } + + #endregion Type-specific collection converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmMetaValueConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmMetaValueConverterTester.cs new file mode 100644 index 000000000..011cc6e9e --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmMetaValueConverterTester.cs @@ -0,0 +1,58 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmMetaValueConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var metaValueMapping = new MetaValueMapping(); + metaValueMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("type")); + var convertedHbmMetaValue = converter.Convert(metaValueMapping); + convertedHbmMetaValue.@class.ShouldEqual(metaValueMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var metaValueMapping = new MetaValueMapping(); + // Don't set anything on the original mapping + var convertedHbmMetaValue = converter.Convert(metaValueMapping); + var blankHbmMetaValue = new HbmMetaValue(); + convertedHbmMetaValue.@class.ShouldEqual(blankHbmMetaValue.@class); + } + + [Test] + public void ShouldConvertValueIfPopulated() + { + var metaValueMapping = new MetaValueMapping(); + metaValueMapping.Set(fluent => fluent.Value, Layer.Conventions, "val"); + var convertedHbmMetaValue = converter.Convert(metaValueMapping); + convertedHbmMetaValue.value.ShouldEqual(metaValueMapping.Value); + } + + [Test] + public void ShouldNotConvertValueIfNotPopulated() + { + var metaValueMapping = new MetaValueMapping(); + // Don't set metaValuething on the original mapping + var convertedHbmMetaValue = converter.Convert(metaValueMapping); + var blankHbmMetaValue = new HbmMetaValue(); + convertedHbmMetaValue.value.ShouldEqual(blankHbmMetaValue.value); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmNaturalIdConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmNaturalIdConverterTester.cs new file mode 100644 index 000000000..922420b3d --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmNaturalIdConverterTester.cs @@ -0,0 +1,56 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmNaturalIdConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var naturalIdMapping = new NaturalIdMapping(); + naturalIdMapping.Set(fluent => fluent.Mutable, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmNaturalId = converter.Convert(naturalIdMapping); + convertedHbmNaturalId.mutable.ShouldEqual(naturalIdMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var naturalIdMapping = new NaturalIdMapping(); + // Don't set anything on the original mapping + var convertedHbmNaturalId = converter.Convert(naturalIdMapping); + var blankHbmNaturalId = new HbmNaturalId(); + convertedHbmNaturalId.mutable.ShouldEqual(blankHbmNaturalId.mutable); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (naturalIdMapping, propertyMapping) => naturalIdMapping.AddProperty(propertyMapping), + hbmNaturalId => hbmNaturalId.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (naturalIdMapping, manyToOneMapping) => naturalIdMapping.AddReference(manyToOneMapping), + hbmNaturalId => hbmNaturalId.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmNestedCompositeElementConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmNestedCompositeElementConverterTester.cs new file mode 100644 index 000000000..2194ee8f2 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmNestedCompositeElementConverterTester.cs @@ -0,0 +1,110 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmNestedCompositeElementConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + nestedCompositeElementMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("t")); + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + convertedHbmNestedCompositeElement.@class.ShouldEqual(nestedCompositeElementMapping.Class); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + // Don't set anything on the original mapping + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + var blankHbmNestedCompositeElement = new HbmNestedCompositeElement(); + convertedHbmNestedCompositeElement.@class.ShouldEqual(blankHbmNestedCompositeElement.@class); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + nestedCompositeElementMapping.Set(fluent => fluent.Name, Layer.Conventions, "testName"); + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + convertedHbmNestedCompositeElement.name.ShouldEqual(nestedCompositeElementMapping.Name); + } + + [Test] + public void ShouldConvertNameIfNotPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + // Don't set anything on the original mapping + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + convertedHbmNestedCompositeElement.name.ShouldEqual(nestedCompositeElementMapping.Name); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + nestedCompositeElementMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + convertedHbmNestedCompositeElement.access.ShouldEqual(nestedCompositeElementMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var nestedCompositeElementMapping = new NestedCompositeElementMapping(); + // Don't set anything on the original mapping + var convertedHbmNestedCompositeElement = converter.Convert(nestedCompositeElementMapping); + var blankHbmNestedCompositeElement = new HbmNestedCompositeElement(); + convertedHbmNestedCompositeElement.access.ShouldEqual(blankHbmNestedCompositeElement.access); + } + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (nestedCompositeElementMapping, propertyMapping) => nestedCompositeElementMapping.AddProperty(propertyMapping), + hbmNestedCompositeElement => hbmNestedCompositeElement.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (nestedCompositeElementMapping, manyToOneMapping) => nestedCompositeElementMapping.AddReference(manyToOneMapping), + hbmNestedCompositeElement => hbmNestedCompositeElement.Items); + } + + [Test] + public void ShouldConvertNestedCompositeElements() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (nestedCompositeElementMapping1, nestedCompositeElementMapping2) => nestedCompositeElementMapping1.AddCompositeElement(nestedCompositeElementMapping2), + hbmNestedCompositeElement => hbmNestedCompositeElement.Items); + } + + [Test] + public void ShouldConvertParent() + { + ShouldConvertSubobjectAsStrictlyTypedField( + (nestedCompositeElementMapping, parentMapping) => nestedCompositeElementMapping.Set(fluent => fluent.Parent, Layer.Defaults, parentMapping), + hbmNestedCompositeElement => hbmNestedCompositeElement.parent); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToManyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToManyConverterTester.cs new file mode 100644 index 000000000..5f837f899 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToManyConverterTester.cs @@ -0,0 +1,91 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmOneToManyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var oneToManyMapping = new OneToManyMapping(); + oneToManyMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference("type")); + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + convertedHbmOneToMany.@class.ShouldEqual(oneToManyMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var oneToManyMapping = new OneToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + var blankHbmOneToMany = new HbmOneToMany(); + convertedHbmOneToMany.@class.ShouldEqual(blankHbmOneToMany.@class); + } + + [Test] + public void ShouldConvertNotFoundIfPopulatedWithValidValue() + { + var notFound = HbmNotFoundMode.Ignore; // Defaults to Exception, so use this to ensure that we can detect changes + + var oneToManyMapping = new OneToManyMapping(); + var notFoundDict = new XmlLinkedEnumBiDictionary(); + oneToManyMapping.Set(fluent => fluent.NotFound, Layer.Conventions, notFoundDict[notFound]); + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + convertedHbmOneToMany.notfound.ShouldEqual(notFound); + } + + [Test] + public void ShouldFailToConvertNotFoundIfPopulatedWithInvalidValue() + { + var oneToManyMapping = new OneToManyMapping(); + oneToManyMapping.Set(fluent => fluent.NotFound, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(oneToManyMapping)); + } + + [Test] + public void ShouldNotConvertNotFoundIfNotPopulated() + { + var oneToManyMapping = new OneToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + var blankHbmOneToMany = new HbmOneToMany(); + convertedHbmOneToMany.notfound.ShouldEqual(blankHbmOneToMany.notfound); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var oneToManyMapping = new OneToManyMapping(); + oneToManyMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + convertedHbmOneToMany.entityname.ShouldEqual(oneToManyMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var oneToManyMapping = new OneToManyMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToMany = converter.Convert(oneToManyMapping); + var blankHbmOneToMany = new HbmOneToMany(); + convertedHbmOneToMany.entityname.ShouldEqual(blankHbmOneToMany.entityname); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToOneConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToOneConverterTester.cs new file mode 100644 index 000000000..5f489813c --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmOneToOneConverterTester.cs @@ -0,0 +1,238 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using FluentNHibernate.Testing.DomainModel; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmOneToOneConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.access.ShouldEqual(oneToOneMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.access.ShouldEqual(blankHbmOneToOne.access); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "cascade"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.cascade.ShouldEqual(oneToOneMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.cascade.ShouldEqual(blankHbmOneToOne.cascade); + } + + [Test] + public void ShouldConvertClassIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Class, Layer.Conventions, new TypeReference(typeof(Record))); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.@class.ShouldEqual(oneToOneMapping.Class.ToString()); + } + + [Test] + public void ShouldNotConvertClassIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.@class.ShouldEqual(blankHbmOneToOne.@class); + } + + [Test] + public void ShouldConvertConstrainedIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Constrained, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.constrained.ShouldEqual(oneToOneMapping.Constrained); + } + + [Test] + public void ShouldNotConvertConstrainedIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.constrained.ShouldEqual(blankHbmOneToOne.constrained); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmFetchMode.Join; // Defaults to Select, so use this to ensure that we can spot changes + + var oneToOneMapping = new OneToOneMapping(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + oneToOneMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmOneToOne.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(oneToOneMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.fetch.ShouldEqual(blankHbmOneToOne.fetch); + Assert.That(convertedHbmOneToOne.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertForeignKeyIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.ForeignKey, Layer.Conventions, "fk"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.foreignkey.ShouldEqual(oneToOneMapping.ForeignKey); + } + + [Test] + public void ShouldNotConvertForeignKeyIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.foreignkey.ShouldEqual(blankHbmOneToOne.foreignkey); + } + + [Test] + public void ShouldConvertLazyIfPopulatedWithValidValue() + { + var lazy = HbmLaziness.Proxy; // Defaults to False, so use this to ensure that we can detect changes + + var oneToOneMapping = new OneToOneMapping(); + var lazyDict = new XmlLinkedEnumBiDictionary(); + oneToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, lazyDict[lazy]); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.lazy.ShouldEqual(lazy); + Assert.That(convertedHbmOneToOne.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertLazyIfPopulatedWithInvalidValue() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Lazy, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(oneToOneMapping)); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.lazy.ShouldEqual(blankHbmOneToOne.lazy); + Assert.That(convertedHbmOneToOne.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.Name, Layer.Conventions, "nm"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.name.ShouldEqual(oneToOneMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.name.ShouldEqual(blankHbmOneToOne.name); + } + + [Test] + public void ShouldConvertPropertyRefIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.PropertyRef, Layer.Conventions, "pr"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.propertyref.ShouldEqual(oneToOneMapping.PropertyRef); + } + + [Test] + public void ShouldNotConvertPropertyRefIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.propertyref.ShouldEqual(blankHbmOneToOne.propertyref); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + oneToOneMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "name1"); + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + convertedHbmOneToOne.entityname.ShouldEqual(oneToOneMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var oneToOneMapping = new OneToOneMapping(); + // Don't set anything on the original mapping + var convertedHbmOneToOne = converter.Convert(oneToOneMapping); + var blankHbmOneToOne = new HbmOneToOne(); + convertedHbmOneToOne.entityname.ShouldEqual(blankHbmOneToOne.entityname); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmParentConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmParentConverterTester.cs new file mode 100644 index 000000000..b1025a921 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmParentConverterTester.cs @@ -0,0 +1,58 @@ +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmParentConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var parentMapping = new ParentMapping(); + parentMapping.Set(fluent => fluent.Name, Layer.Conventions, "testName"); + var convertedHbmParent = converter.Convert(parentMapping); + convertedHbmParent.name.ShouldEqual(parentMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var parentMapping = new ParentMapping(); + // Don't set anything on the original mapping + var convertedHbmParent = converter.Convert(parentMapping); + var blankHbmParent = new HbmParent(); + convertedHbmParent.name.ShouldEqual(blankHbmParent.name); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var parentMapping = new ParentMapping(); + parentMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmParent = converter.Convert(parentMapping); + convertedHbmParent.access.ShouldEqual(parentMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var parentMapping = new ParentMapping(); + // Don't set anything on the original mapping + var convertedHbmParent = converter.Convert(parentMapping); + var blankHbmParent = new HbmParent(); + convertedHbmParent.access.ShouldEqual(blankHbmParent.access); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmPropertyConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmPropertyConverterTester.cs new file mode 100644 index 000000000..1fd915173 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmPropertyConverterTester.cs @@ -0,0 +1,216 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmPropertyConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.access.ShouldEqual(propertyMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.access.ShouldEqual(blankHbmProperty.access); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.name.ShouldEqual(propertyMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.name.ShouldEqual(blankHbmProperty.name); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference(typeof(HbmPropertyConverterTester))); // Can be any class, this one is just guaranteed to exist + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.type1.ShouldEqual(propertyMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.type1.ShouldEqual(blankHbmProperty.type1); + } + + [Test] + public void ShouldConvertFormulaIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Formula, Layer.Conventions, "form"); + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.formula.ShouldEqual(propertyMapping.Formula); + } + + [Test] + public void ShouldNotConvertFormulaIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.formula.ShouldEqual(blankHbmProperty.formula); + } + + [Test] + public void ShouldConvertGeneratedIfPopulatedWithValidValue() + { + var generated = HbmPropertyGeneration.Always; // Defaults to Never, use this to ensure that we can detect changes + + var propertyMapping = new PropertyMapping(); + var genDict = new XmlLinkedEnumBiDictionary(); + propertyMapping.Set(fluent => fluent.Generated, Layer.Conventions, genDict[generated]); + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.generated.ShouldEqual(generated); + } + + [Test] + public void ShouldFailToConvertGeneratedIfPopulatedWithInvalidValue() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Generated, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(propertyMapping)); + } + + [Test] + public void ShouldNotConvertGeneratedIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.generated.ShouldEqual(blankHbmProperty.generated); + } + + [Test] + public void ShouldConvertInsertIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Insert, Layer.Conventions, true); // Defaults to false, so use this to ensure we can detect changes + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.insert.ShouldEqual(propertyMapping.Insert); + Assert.That(convertedHbmProperty.insertSpecified.Equals(true), "Insert was not marked as specified"); + } + + [Test] + public void ShouldNotConvertInsertIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.insert.ShouldEqual(blankHbmProperty.insert); + Assert.That(convertedHbmProperty.insertSpecified.Equals(false), "Insert was marked as specified"); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure we can detect changes + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.optimisticlock.ShouldEqual(propertyMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.optimisticlock.ShouldEqual(blankHbmProperty.optimisticlock); + } + + [Test] + public void ShouldConvertUpdateIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Update, Layer.Conventions, true); // Defaults to false, so use this to ensure we can detect changes + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.update.ShouldEqual(propertyMapping.Update); + Assert.That(convertedHbmProperty.updateSpecified.Equals(true), "Update was not marked as specified"); + } + + [Test] + public void ShouldNotConvertUpdateIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.update.ShouldEqual(blankHbmProperty.update); + Assert.That(convertedHbmProperty.updateSpecified.Equals(false), "Update was marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var propertyMapping = new PropertyMapping(); + propertyMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); // Defaults to false, so use this to ensure we can detect changes + var convertedHbmProperty = converter.Convert(propertyMapping); + convertedHbmProperty.lazy.ShouldEqual(propertyMapping.Lazy); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var propertyMapping = new PropertyMapping(); + // Don't set anything on the original mapping + var convertedHbmProperty = converter.Convert(propertyMapping); + var blankHbmProperty = new HbmProperty(); + convertedHbmProperty.lazy.ShouldEqual(blankHbmProperty.lazy); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + (propertyMapping, columnMapping) => propertyMapping.AddColumn(Layer.Defaults, columnMapping), + hbmProperty => hbmProperty.Items); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmSetConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmSetConverterTester.cs new file mode 100644 index 000000000..4c64b56a7 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmSetConverterTester.cs @@ -0,0 +1,511 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmSetConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Base collection attribute value field tests + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Access, Layer.Conventions, "acc"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.access.ShouldEqual(setMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.access.ShouldEqual(blankHbmSet.access); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.batchsize.ShouldEqual(setMapping.BatchSize); + Assert.That(convertedHbmSet.batchsizeSpecified.Equals(true), "Batch size was not marked as specified"); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.batchsize.ShouldEqual(blankHbmSet.batchsize); + Assert.That(convertedHbmSet.batchsizeSpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertCascadeIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Cascade, Layer.Conventions, "all"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.cascade.ShouldEqual(setMapping.Cascade); + } + + [Test] + public void ShouldNotConvertCascadeIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.cascade.ShouldEqual(blankHbmSet.cascade); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.check.ShouldEqual(setMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.check.ShouldEqual(blankHbmSet.check); + } + + [Test] + public void ShouldConvertCollectionTypeIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, new TypeReference("type")); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.collectiontype.ShouldEqual(setMapping.CollectionType.ToString()); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfEmpty() + { + var setMapping = CollectionMapping.Set(); + // Set an explicitly empty type reference + setMapping.Set(fluent => fluent.CollectionType, Layer.Conventions, TypeReference.Empty); + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.collectiontype.ShouldEqual(blankHbmSet.collectiontype); + } + + [Test] + public void ShouldNotConvertCollectionTypeIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.collectiontype.ShouldEqual(blankHbmSet.collectiontype); + } + + [Test] + public void ShouldConvertFetchIfPopulatedWithValidValue() + { + var fetch = HbmCollectionFetchMode.Subselect; // Defaults to Select, so use something else to properly detect that it changes + + var setMapping = CollectionMapping.Set(); + var fetchDict = new XmlLinkedEnumBiDictionary(); + setMapping.Set(fluent => fluent.Fetch, Layer.Conventions, fetchDict[fetch]); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.fetch.ShouldEqual(fetch); + Assert.That(convertedHbmSet.fetchSpecified.Equals(true), "Fetch was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertFetchIfPopulatedWithInvalidValue() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Fetch, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(setMapping)); + } + + [Test] + public void ShouldNotConvertFetchIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.fetch.ShouldEqual(blankHbmSet.fetch); + Assert.That(convertedHbmSet.fetchSpecified.Equals(false), "Fetch was marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_True() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Generic, Layer.Conventions, true); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.generic.ShouldEqual(setMapping.Generic); + Assert.That(convertedHbmSet.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldConvertGenericIfPopulated_False() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Generic, Layer.Conventions, false); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.generic.ShouldEqual(setMapping.Generic); + Assert.That(convertedHbmSet.genericSpecified.Equals(true), "Generic was not marked as specified"); + } + + [Test] + public void ShouldNotConvertGenericIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.generic.ShouldEqual(blankHbmSet.generic); + Assert.That(convertedHbmSet.genericSpecified.Equals(false), "Generic was marked as specified"); + } + + [Test] + public void ShouldConvertInverseIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Inverse, Layer.Conventions, true); // Defaults to false, so use this to ensure that we can detect changes + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.inverse.ShouldEqual(setMapping.Inverse); + } + + [Test] + public void ShouldNotConvertInverseIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.inverse.ShouldEqual(blankHbmSet.inverse); + } + + [Test] + public void ShouldConvertLazyIfPopulated() + { + var hbmLazy = HbmCollectionLazy.False; // Defaults to True, so use something else to properly detect that it changes + + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Lazy, Layer.Conventions, HbmCollectionConverter.FluentHbmLazyBiDict[hbmLazy]); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.lazy.ShouldEqual(hbmLazy); + Assert.That(convertedHbmSet.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + // Since it is enum-based, Lazy cannot contain any invalid values, so no need to test for that here + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.lazy.ShouldEqual(blankHbmSet.lazy); + Assert.That(convertedHbmSet.lazySpecified.Equals(false), "Lazy was marked as specified"); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.name.ShouldEqual(setMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.name.ShouldEqual(blankHbmSet.name); + } + + [Test] + public void ShouldConvertOptimisticLockIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.OptimisticLock, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.optimisticlock.ShouldEqual(setMapping.OptimisticLock); + } + + [Test] + public void ShouldNotConvertOptimisticLockIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.optimisticlock.ShouldEqual(blankHbmSet.optimisticlock); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(string))); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.persister.ShouldEqual(setMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.persister.ShouldEqual(blankHbmSet.persister); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.schema.ShouldEqual(setMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.schema.ShouldEqual(blankHbmSet.schema); + } + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.table.ShouldEqual(setMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.table.ShouldEqual(blankHbmSet.table); + } + + [Test] + public void ShouldConvertWhereIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Where, Layer.Conventions, "x = 1"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.where.ShouldEqual(setMapping.Where); + } + + [Test] + public void ShouldNotConvertWhereIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.where.ShouldEqual(blankHbmSet.where); + } + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.subselect.Text.ShouldEqual(new string[] { setMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.subselect.ShouldEqual(blankHbmSet.subselect); + } + + [Test] + public void ShouldConvertMutableIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Mutable, Layer.Conventions, false); // Defaults to true, so use this to ensure that we can detect changes + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.mutable.ShouldEqual(setMapping.Mutable); + } + + [Test] + public void ShouldNotConvertMutableIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.mutable.ShouldEqual(blankHbmSet.mutable); + } + + #endregion Base collection attribute value field tests + + #region Type-specific collection attribute value field tests + + [Test] + public void ShouldConvertOrderByIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.OrderBy, Layer.Conventions, "ord"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.orderby.ShouldEqual(setMapping.OrderBy); + } + + [Test] + public void ShouldNotConvertOrderByIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.orderby.ShouldEqual(blankHbmSet.orderby); + } + + [Test] + public void ShouldConvertSortIfPopulated() + { + var setMapping = CollectionMapping.Set(); + setMapping.Set(fluent => fluent.Sort, Layer.Conventions, "asc"); + var convertedHbmSet = converter.Convert(setMapping); + convertedHbmSet.sort.ShouldEqual(setMapping.Sort); + } + + [Test] + public void ShouldNotConvertSortIfNotPopulated() + { + var setMapping = CollectionMapping.Set(); + // Don't set anything on the original mapping + var convertedHbmSet = converter.Convert(setMapping); + var blankHbmSet = new HbmSet(); + convertedHbmSet.sort.ShouldEqual(blankHbmSet.sort); + } + + #endregion Type-specific collection attribute value field tests + + #region Base collection converter-based subobject tests + + [Test] + public void ShouldConvertKey() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Set(), + (setMapping, keyMapping) => setMapping.Set(fluent => fluent.Key, Layer.Defaults, keyMapping), + hbmSet => hbmSet.key); + } + + [Test] + public void ShouldConvertICollectionRelationship_OneToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Set(), + () => new OneToManyMapping(), + (setMapping, icrMapping) => setMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmSet => hbmSet.Item); + } + + [Test] + public void ShouldConvertICollectionRelationship_ManyToMany() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Set(), + () => new ManyToManyMapping(), + (setMapping, icrMapping) => setMapping.Set(fluent => fluent.Relationship, Layer.Defaults, icrMapping), + hbmSet => hbmSet.Item); + } + + [Test] + public void ShouldConvertCache() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => CollectionMapping.Set(), + (setMapping, cacheMapping) => setMapping.Set(fluent => fluent.Cache, Layer.Defaults, cacheMapping), + hbmSet => hbmSet.cache); + } + + [Test] + public void ShouldConvertCompositeElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Set(), + (setMapping, compositeElementMapping) => setMapping.Set(fluent => fluent.CompositeElement, Layer.Defaults, compositeElementMapping), + hbmSet => hbmSet.Item); + } + + [Test] + public void ShouldConvertElement() + { + ShouldConvertSubobjectAsLooselyTypedField( + () => CollectionMapping.Set(), + (setMapping, elementMapping) => setMapping.Set(fluent => fluent.Element, Layer.Defaults, elementMapping), + hbmSet => hbmSet.Item); + } + + [Test] + public void ShouldConvertFilters() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => CollectionMapping.Set(), + (setMapping, filterMapping) => setMapping.AddFilter(filterMapping), + hbmSet => hbmSet.filter); + } + + #endregion Base collection converter-based subobject tests + + #region Type-specific collection converter-based subobject tests + + // No tests for this type + + #endregion Type-specific collection converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmStoredProcedureConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmStoredProcedureConverterTester.cs new file mode 100644 index 000000000..1c251bd47 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmStoredProcedureConverterTester.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmHbmStoredProcedureConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertQueryIfPopulated() + { + var storedProcedureMapping = new StoredProcedureMapping(); + storedProcedureMapping.Set(fluent => fluent.Query, Layer.Conventions, "update ABC"); + var convertedHbmCustomSQL = converter.Convert(storedProcedureMapping); + convertedHbmCustomSQL.Text.ShouldEqual(new string[] { storedProcedureMapping.Query }); + } + + [Test] + public void ShouldConvertQueryIfNotPopulated() + { + var storedProcedureMapping = new StoredProcedureMapping(); + // Don't set the anything on the original mapping + var convertedHbmCustomSQL = converter.Convert(storedProcedureMapping); + // Check that it was converted, even if nothing was set + convertedHbmCustomSQL.Text.ShouldEqual(new string[] { storedProcedureMapping.Query }); + } + + [Test] + public void ShouldConvertCheckIfPopulatedWithValidValue() + { + var check = HbmCustomSQLCheck.Rowcount; // Defaults to None, so use this to ensure that we can detect changes + + var storedProcedureMapping = new StoredProcedureMapping(); + var checkDict = new XmlLinkedEnumBiDictionary(); + storedProcedureMapping.Set(fluent => fluent.Check, Layer.Conventions, checkDict[check]); + var convertedHbmCustomSQL = converter.Convert(storedProcedureMapping); + convertedHbmCustomSQL.check.ShouldEqual(check); + Assert.That(convertedHbmCustomSQL.checkSpecified.Equals(true), "Check was not marked as specified"); + } + + [Test] + public void ShouldFailToConvertCheckIfPopulatedWithInvalidValue() + { + var storedProcedureMapping = new StoredProcedureMapping(); + storedProcedureMapping.Set(fluent => fluent.Check, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(storedProcedureMapping)); + } + + // This one is weird: because the default is an empty string rather than null, it is considered "specified"... + [Test] + public void ShouldConvertCheckIfNotPopulated() + { + var storedProcedureMapping = new StoredProcedureMapping(); + // Don't set the anything on the original mapping + var convertedHbmCustomSQL = converter.Convert(storedProcedureMapping); + var checkDict = new XmlLinkedEnumBiDictionary(); + convertedHbmCustomSQL.check.ShouldEqual(checkDict[storedProcedureMapping.Check]); + Assert.That(convertedHbmCustomSQL.checkSpecified.Equals(true), "Check was not marked as specified"); + } + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmSubclassConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmSubclassConverterTester.cs new file mode 100644 index 000000000..51b675a1c --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmSubclassConverterTester.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using FakeItEasy; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmSubclassConverterTester + { + // No use for the normal setup method to populate the container, since no test uses it + + [Test] + public void ShouldProcessSubclassAsBasicSubclass() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => new SubclassMapping(SubclassType.Subclass) + ); + } + + [Test] + public void ShouldProcessJoinedSubclassAsJoinedSubclass() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => new SubclassMapping(SubclassType.JoinedSubclass) + ); + } + + [Test] + public void ShouldProcessUnionSubclassAsUnionSubclass() + { + ShouldConvertSpecificHbmForMappingSubtype( + () => new SubclassMapping(SubclassType.UnionSubclass) + ); + } + + /* Unfortunately, there is no good way to test the "fail if passed something unsupported" logic, because we cannot + * generate a "bad" SubclassType and we want to support all of the real ones. + */ + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmTuplizerConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmTuplizerConverterTester.cs new file mode 100644 index 000000000..b201ea266 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmTuplizerConverterTester.cs @@ -0,0 +1,80 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmTuplizerConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertModeIfPopulated() + { + var hbmEntityMode = HbmTuplizerEntitymode.DynamicMap; // Defaults to Poco, so use something else to properly detect that it changes + + var tuplizerMapping = new TuplizerMapping(); + tuplizerMapping.Set(fluent => fluent.Mode, Layer.Conventions, HbmTuplizerConverter.FluentHbmEntityModeBiDict[hbmEntityMode]); + var convertedHbmTuplizer = converter.Convert(tuplizerMapping); + convertedHbmTuplizer.entitymode.ShouldEqual(hbmEntityMode); + Assert.That(convertedHbmTuplizer.entitymodeSpecified.Equals(true), "Entity mode was not marked as specified"); + } + + // This test shouldn't really be possible, since it relies on the existence of a value in TuplizerMode that does not have + // an equivalent in HbmTuplizerEntitymode, which really should not be the case (the value is also not present in the XSD). + // But for as long as it is defined, it is possible for someone to try to use it, and thus valuable to test that we reject + // it properly. + [Test] + public void ShouldFailToConvertModeIfPopulatedWithInvalidValue() + { + var tuplizerMapping = new TuplizerMapping(); + tuplizerMapping.Set(fluent => fluent.Mode, Layer.Conventions, TuplizerMode.Xml); + Assert.Throws(() => converter.Convert(tuplizerMapping)); + } + + [Test] + public void ShouldNotConvertModeIfNotPopulated() + { + var tuplizerMapping = new TuplizerMapping(); + // Don't set anything on the original mapping + var convertedHbmTuplizer = converter.Convert(tuplizerMapping); + var blankHbmTuplizer = new HbmTuplizer(); + convertedHbmTuplizer.entitymode.ShouldEqual(blankHbmTuplizer.entitymode); + Assert.That(convertedHbmTuplizer.entitymodeSpecified.Equals(false), "Entity mode was marked as specified"); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + Type tuplizerType = typeof(NHibernate.Tuple.Entity.PocoEntityTuplizer); + + var tuplizerMapping = new TuplizerMapping(); + tuplizerMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference(tuplizerType)); + var convertedHbmTuplizer = converter.Convert(tuplizerMapping); + convertedHbmTuplizer.@class.ShouldEqual(tuplizerMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var tuplizerMapping = new TuplizerMapping(); + // Don't set anything on the original mapping + var convertedHbmTuplizer = converter.Convert(tuplizerMapping); + var blankHbmTuplizer = new HbmTuplizer(); + convertedHbmTuplizer.@class.ShouldEqual(blankHbmTuplizer.@class); + } + + // The XML variant tests for EntityName handling, but writes it to an attribute that isn't actually defined in the XSD, + // nor is it available on HbmTuplizer. Given that fact, we don't support it. + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmUnionSubclassConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmUnionSubclassConverterTester.cs new file mode 100644 index 000000000..6091f6d5c --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmUnionSubclassConverterTester.cs @@ -0,0 +1,537 @@ +using System; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Output; +using NHibernate.Cfg.MappingSchema; +using NUnit.Framework; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmUnionSubclassConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + #region Value field tests + + [Test] + public void ShouldConvertTableNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.TableName, Layer.Conventions, "tbl"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.table.ShouldEqual(subclassMapping.TableName); + } + + [Test] + public void ShouldNotConvertTableNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.table.ShouldEqual(blankHbmUnionSubclass.table); + } + + [Test] + public void ShouldConvertSchemaIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Schema, Layer.Conventions, "dbo"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.schema.ShouldEqual(subclassMapping.Schema); + } + + [Test] + public void ShouldNotConvertSchemaIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.schema.ShouldEqual(blankHbmUnionSubclass.schema); + } + + [Test] + public void ShouldConvertCheckIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Check, Layer.Conventions, "chk"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.check.ShouldEqual(subclassMapping.Check); + } + + [Test] + public void ShouldNotConvertCheckIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.check.ShouldEqual(blankHbmUnionSubclass.check); + } + + [Test] + public void ShouldConvertPersisterIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Persister, Layer.Conventions, new TypeReference(typeof(HbmUnionSubclassConverterTester))); // Not really representative, but the class is guaranteed to exist + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.persister.ShouldEqual(subclassMapping.Persister.ToString()); + } + + [Test] + public void ShouldNotConvertPersisterIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.persister.ShouldEqual(blankHbmUnionSubclass.persister); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.name.ShouldEqual(subclassMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.name.ShouldEqual(blankHbmUnionSubclass.name); + } + + [Test] + public void ShouldConvertProxyIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Proxy, Layer.Conventions, "p"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.proxy.ShouldEqual(subclassMapping.Proxy); + } + + [Test] + public void ShouldNotConvertProxyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.proxy.ShouldEqual(blankHbmUnionSubclass.proxy); + } + + [Test] + public void ShouldConvertLazyIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, true); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmUnionSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldConvertLazyIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Lazy, Layer.Conventions, false); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.lazy.ShouldEqual(subclassMapping.Lazy); + Assert.That(convertedHbmUnionSubclass.lazySpecified.Equals(true), "Lazy was not marked as specified"); + } + + [Test] + public void ShouldNotConvertLazyIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.lazy.ShouldEqual(blankHbmUnionSubclass.lazy); + Assert.That(convertedHbmUnionSubclass.lazySpecified.Equals(false), "Batch size was marked as specified"); + } + + [Test] + public void ShouldConvertDynamicUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.DynamicUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.dynamicupdate.ShouldEqual(subclassMapping.DynamicUpdate); + } + + [Test] + public void ShouldNotConvertDynamicUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.dynamicupdate.ShouldEqual(blankHbmUnionSubclass.dynamicupdate); + } + + [Test] + public void ShouldConvertDynamicInsertIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.DynamicInsert, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.dynamicinsert.ShouldEqual(subclassMapping.DynamicInsert); + } + + [Test] + public void ShouldNotConvertDynamicInsertIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.dynamicinsert.ShouldEqual(blankHbmUnionSubclass.dynamicinsert); + } + + [Test] + public void ShouldConvertSelectBeforeUpdateIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.SelectBeforeUpdate, Layer.Conventions, true); // Defaults to false, so we have to set it true here in order to tell if it actually changed + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.selectbeforeupdate.ShouldEqual(subclassMapping.SelectBeforeUpdate); + } + + [Test] + public void ShouldNotConvertSelectBeforeUpdateIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.selectbeforeupdate.ShouldEqual(blankHbmUnionSubclass.selectbeforeupdate); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_True() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, true); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmUnionSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldConvertAbstractIfPopulated_False() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Abstract, Layer.Conventions, false); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.@abstract.ShouldEqual(subclassMapping.Abstract); + Assert.That(convertedHbmUnionSubclass.abstractSpecified.Equals(true), "Abstract was not marked as specified"); + } + + [Test] + public void ShouldNotConvertAbstractIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.@abstract.ShouldEqual(blankHbmUnionSubclass.@abstract); + Assert.That(convertedHbmUnionSubclass.abstractSpecified.Equals(false), "Abstract was marked as specified"); + } + + [Test] + public void ShouldConvertEntityNameIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.EntityName, Layer.Conventions, "entity1"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.entityname.ShouldEqual(subclassMapping.EntityName); + } + + [Test] + public void ShouldNotConvertEntityNameIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.entityname.ShouldEqual(blankHbmUnionSubclass.entityname); + } + + [Test] + public void ShouldConvertBatchSizeIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.BatchSize, Layer.Conventions, 10); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.batchsize.ShouldEqual(subclassMapping.BatchSize.ToString()); + } + + [Test] + public void ShouldNotConvertBatchSizeIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.batchsize.ShouldEqual(blankHbmUnionSubclass.batchsize); + } + + #endregion Value field tests + + #region Non-converter-based subobject tests + + [Test] + public void ShouldConvertSubselectIfPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.Set(fluent => fluent.Subselect, Layer.Conventions, "val"); + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + convertedHbmUnionSubclass.subselect.Text.ShouldEqual(new string[] { subclassMapping.Subselect }); + } + + [Test] + public void ShouldNotConvertSubselectIfNotPopulated() + { + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + // Don't set anything on the original mapping + var convertedHbmUnionSubclass = converter.Convert(subclassMapping); + var blankHbmUnionSubclass = new HbmUnionSubclass(); + convertedHbmUnionSubclass.subselect.ShouldEqual(blankHbmUnionSubclass.subselect); + } + + #endregion Non-converter-based subobject tests + + #region Converter-based subobject tests + + [Test] + public void ShouldConvertProperties() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + (subclassMapping, propertyMapping) => subclassMapping.AddProperty(propertyMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertManyToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + (subclassMapping, manyToOneMapping) => subclassMapping.AddReference(manyToOneMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertOneToOnes() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + (subclassMapping, oneToOneMapping) => subclassMapping.AddOneToOne(oneToOneMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_Component() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new ComponentMapping(ComponentType.Component), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertComponents_DynamicComponent() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new ComponentMapping(ComponentType.DynamicComponent), + (subclassMapping, componentMapping) => subclassMapping.AddComponent(componentMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertAnys() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + (subclassMapping, anyMapping) => subclassMapping.AddAny(anyMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Map() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => CollectionMapping.Map(), + (subclassMapping, mapMapping) => subclassMapping.AddCollection(mapMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Set() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => CollectionMapping.Set(), + (subclassMapping, setMapping) => subclassMapping.AddCollection(setMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_List() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => CollectionMapping.List(), + (subclassMapping, listMapping) => subclassMapping.AddCollection(listMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test] + public void ShouldConvertCollections_Bag() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => CollectionMapping.Bag(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_IdBag")] + public void ShouldConvertCollections_IdBag() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertCollections_Array() + { + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => CollectionMapping.Array(), + (subclassMapping, bagMapping) => subclassMapping.AddCollection(bagMapping), + hbmUnionSubclass => hbmUnionSubclass.Items); + } + + [Test, Ignore("ShouldConvertCollections_PrimitiveArray")] + public void ShouldConvertCollections_PrimitiveArray() + { + Assert.Fail("Target logic not yet available"); + } + + [Test] + public void ShouldConvertSubclasses_Subclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new SubclassMapping(SubclassType.Subclass), + (unionSubclassMapping, subclassMapping) => unionSubclassMapping.AddSubclass(subclassMapping), + hbmUnionSubclass => hbmUnionSubclass.unionsubclass1) + ); + } + + [Test] + public void ShouldConvertSubclasses_JoinedSubclass() + { + Assert.Throws(() => + ShouldConvertSubobjectsAsLooselyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new SubclassMapping(SubclassType.JoinedSubclass), + (unionSubclassMapping, joinedSubclassMapping) => unionSubclassMapping.AddSubclass(joinedSubclassMapping), + hbmUnionSubclass => hbmUnionSubclass.unionsubclass1) + ); + } + + [Test] + public void ShouldConvertSubclasses_UnionSubclass() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new SubclassMapping(SubclassType.UnionSubclass), + (unionSubclassMapping1, unionSubclassMapping2) => unionSubclassMapping1.AddSubclass(unionSubclassMapping2), + hbmUnionSubclass => hbmUnionSubclass.unionsubclass1); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlInsert() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new StoredProcedureMapping("sql-insert", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmUnionSubclass => hbmUnionSubclass.sqlinsert); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlUpdate() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new StoredProcedureMapping("sql-update", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmUnionSubclass => hbmUnionSubclass.sqlupdate); + } + + [Test] + public void ShouldConvertStoredProcedure_SqlDelete() + { + ShouldConvertSubobjectAsStrictlyTypedField( + () => new SubclassMapping(SubclassType.UnionSubclass), + () => new StoredProcedureMapping("sql-delete", ""), + (subclassMapping, storedProcedureMapping) => subclassMapping.AddStoredProcedure(storedProcedureMapping), + hbmUnionSubclass => hbmUnionSubclass.sqldelete); + } + + [Test] + public void ShouldConvertStoredProcedure_Unsupported() + { + var unsupportedSPType = "invalid"; + + // Set up a fake converter + var fakeConverter = A.Fake>(); + + // Set up a custom container with the fake FSub->HSub converter registered, and obtain our main converter from it (so + // that it will use the fake implementation). Note that we do the resolution _before_ we register the fake, so that + // in cases where we are doing recursive types and FMain == FSub + HMain == HSub (e.g., subclasses-of-subclasses) we + // get the real converter for the "outer" call but the fake for any "inner" calls. + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + container.Register>(cnvrt => fakeConverter); + + // Allocate the subclass mapping and a stored procedure submapping with an unsupported sptype + var subclassMapping = new SubclassMapping(SubclassType.UnionSubclass); + subclassMapping.AddStoredProcedure(new StoredProcedureMapping(unsupportedSPType, "")); + + // This should throw + Assert.Throws(() => converter.Convert(subclassMapping)); + + // We don't care if it made a call to the subobject conversion logic or not (it is low enough cost that it doesn't + // really matter in the case of failure, and some implementation approaches that uses this may be simpler). + } + + #endregion Converter-based subobject tests + } +} diff --git a/src/FluentNHibernate.Testing/MappingModel/Output/HbmVersionConverterTester.cs b/src/FluentNHibernate.Testing/MappingModel/Output/HbmVersionConverterTester.cs new file mode 100644 index 000000000..e8bd4d054 --- /dev/null +++ b/src/FluentNHibernate.Testing/MappingModel/Output/HbmVersionConverterTester.cs @@ -0,0 +1,136 @@ +using System; +using FluentNHibernate.MappingModel; +using FluentNHibernate.MappingModel.Output; +using NUnit.Framework; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.Testing.Hbm.HbmConverterTestHelper; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmVersionConverterTester + { + private IHbmConverter converter; + + [SetUp] + public void GetConverterFromContainer() + { + var container = new HbmConverterContainer(); + converter = container.Resolve>(); + } + + [Test] + public void ShouldConvertAccessIfPopulated() + { + var versionMapping = new VersionMapping(); + versionMapping.Set(fluent => fluent.Access, Layer.Conventions, "access"); + var convertedHbmVersion = converter.Convert(versionMapping); + convertedHbmVersion.access.ShouldEqual(versionMapping.Access); + } + + [Test] + public void ShouldNotConvertAccessIfNotPopulated() + { + var versionMapping = new VersionMapping(); + // Don't set anything on the original mapping + var convertedHbmVersion = converter.Convert(versionMapping); + var blankHbmVersion = new HbmVersion(); + convertedHbmVersion.access.ShouldEqual(blankHbmVersion.access); + } + + [Test] + public void ShouldConvertGeneratedIfPopulatedWithValidValue() + { + var generated = HbmVersionGeneration.Always; // Defaults to Never, so use this to ensure that we can detect changes + + var versionMapping = new VersionMapping(); + var generatedDict = new XmlLinkedEnumBiDictionary(); + versionMapping.Set(fluent => fluent.Generated, Layer.Conventions, generatedDict[generated]); + var convertedHbmVersion = converter.Convert(versionMapping); + convertedHbmVersion.generated.ShouldEqual(generated); + } + + [Test] + public void ShouldFailToConvertGeneratedIfPopulatedWithInvalidValue() + { + var versionMapping = new VersionMapping(); + versionMapping.Set(fluent => fluent.Generated, Layer.Conventions, "invalid_value"); + Assert.Throws(() => converter.Convert(versionMapping)); + } + + [Test] + public void ShouldNotConvertGeneratedIfNotPopulated() + { + var versionMapping = new VersionMapping(); + // Don't set anything on the original mapping + var convertedHbmVersion = converter.Convert(versionMapping); + var blankHbmVersion = new HbmVersion(); + convertedHbmVersion.generated.ShouldEqual(blankHbmVersion.generated); + } + + [Test] + public void ShouldConvertNameIfPopulated() + { + var versionMapping = new VersionMapping(); + versionMapping.Set(fluent => fluent.Name, Layer.Conventions, "name"); + var convertedHbmVersion = converter.Convert(versionMapping); + convertedHbmVersion.name.ShouldEqual(versionMapping.Name); + } + + [Test] + public void ShouldNotConvertNameIfNotPopulated() + { + var versionMapping = new VersionMapping(); + // Don't set anything on the original mapping + var convertedHbmVersion = converter.Convert(versionMapping); + var blankHbmVersion = new HbmVersion(); + convertedHbmVersion.name.ShouldEqual(blankHbmVersion.name); + } + + [Test] + public void ShouldConvertTypeIfPopulated() + { + var versionMapping = new VersionMapping(); + versionMapping.Set(fluent => fluent.Type, Layer.Conventions, new TypeReference("type")); + var convertedHbmVersion = converter.Convert(versionMapping); + convertedHbmVersion.type.ShouldEqual(versionMapping.Type.ToString()); + } + + [Test] + public void ShouldNotConvertTypeIfNotPopulated() + { + var versionMapping = new VersionMapping(); + // Don't set anything on the original mapping + var convertedHbmVersion = converter.Convert(versionMapping); + var blankHbmVersion = new HbmVersion(); + convertedHbmVersion.type.ShouldEqual(blankHbmVersion.type); + } + + [Test] + public void ShouldConvertUnsavedValueIfPopulated() + { + var versionMapping = new VersionMapping(); + versionMapping.Set(fluent => fluent.UnsavedValue, Layer.Conventions, "u-value"); + var convertedHbmVersion = converter.Convert(versionMapping); + convertedHbmVersion.unsavedvalue.ShouldEqual(versionMapping.UnsavedValue); + } + + [Test] + public void ShouldNotConvertUnsavedValueIfNotPopulated() + { + var versionMapping = new VersionMapping(); + // Don't set anything on the original mapping + var convertedHbmVersion = converter.Convert(versionMapping); + var blankHbmVersion = new HbmVersion(); + convertedHbmVersion.unsavedvalue.ShouldEqual(blankHbmVersion.unsavedvalue); + } + + [Test] + public void ShouldConvertColumns() + { + ShouldConvertSubobjectsAsStrictlyTypedArray( + (versionMapping, columnMapping) => versionMapping.AddColumn(Layer.Defaults, columnMapping), + hbmVersion => hbmVersion.column); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/PersistenceModelTests/BasicPersistenceModelTests.cs b/src/FluentNHibernate.Testing/PersistenceModelTests/BasicPersistenceModelTests.cs new file mode 100644 index 000000000..39b9ae47e --- /dev/null +++ b/src/FluentNHibernate.Testing/PersistenceModelTests/BasicPersistenceModelTests.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using FakeItEasy; +using FluentNHibernate.MappingModel; +using NHibernate.Cfg; +using NUnit.Framework; +using static FluentNHibernate.Testing.Cfg.SQLiteFrameworkConfigurationFactory; + +namespace FluentNHibernate.Testing.PersistenceModelTests +{ + [TestFixture] + public class BasicPersistenceModelTests + { + private Configuration cfg; + + [SetUp] + public void CreateConfig() + { + cfg = new Configuration(); + + CreateStandardInMemoryConfiguration() + .ConfigureProperties(cfg); + } + + [Test] + public void ShouldInvokeMappingApplicationStrategy() + { + var mockStrategy = A.Fake(); + + var model = new PersistenceModel(); + model.MappingApplicationStrategy = mockStrategy; + + model.Configure(cfg); + + A.CallTo(() => mockStrategy.ApplyMappingsToConfiguration(A>.Ignored, A.Ignored, A.Ignored)).MustHaveHappened(Repeated.Exactly.Once); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate.Testing/Utils/HbmExtensionsTester.cs b/src/FluentNHibernate.Testing/Utils/HbmExtensionsTester.cs new file mode 100644 index 000000000..caee12508 --- /dev/null +++ b/src/FluentNHibernate.Testing/Utils/HbmExtensionsTester.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using NHibernate; +using NHibernate.Type; +using NUnit.Framework; + +namespace FluentNHibernate.Testing.MappingModel.Output +{ + [TestFixture] + public class HbmExtensionsTester + { + [Test] + public void ShouldConvertHbmParam() + { + var paramPair = new KeyValuePair("george", "fred"); + + var convertedParameter = FluentNHibernate.Utils.HbmExtensions.ToHbmParam(paramPair); + + convertedParameter.ShouldNotBeNull(); + convertedParameter.name.ShouldEqual(paramPair.Key); + convertedParameter.Text.ShouldEqual(new string[] { paramPair.Value }); + } + + [Test] + public void ShouldConvertHbmFilterParam() + { + var paramPair = new KeyValuePair("george", NHibernateUtil.Int32); + + var convertedParameter = FluentNHibernate.Utils.HbmExtensions.ToHbmFilterParam(paramPair); + + convertedParameter.ShouldNotBeNull(); + convertedParameter.name.ShouldEqual(paramPair.Key); + convertedParameter.type.ShouldEqual(paramPair.Value.Name); + } + } +} diff --git a/src/FluentNHibernate/Cfg/FluentConfiguration.cs b/src/FluentNHibernate/Cfg/FluentConfiguration.cs index 63634b3e5..666157f22 100644 --- a/src/FluentNHibernate/Cfg/FluentConfiguration.cs +++ b/src/FluentNHibernate/Cfg/FluentConfiguration.cs @@ -241,6 +241,14 @@ public ISessionFactory BuildSessionFactory() /// /// NHibernate Configuration instance public Configuration BuildConfiguration() + { + return BuildConfiguration(1); + } + /// + /// Verifies the configuration and populates the NHibernate Configuration instance. + /// + /// NHibernate Configuration instance + public Configuration BuildConfiguration(int degreeOfParallelism) { try { @@ -249,7 +257,7 @@ public Configuration BuildConfiguration() foreach (var builder in mappingsBuilders) builder(mappingCfg); - mappingCfg.Apply(Configuration); + mappingCfg.Apply(Configuration, degreeOfParallelism); if (cache.IsDirty) Configuration.AddProperties(cache.Create()); diff --git a/src/FluentNHibernate/Cfg/MappingConfiguration.cs b/src/FluentNHibernate/Cfg/MappingConfiguration.cs index f1d616dd9..17c86206c 100644 --- a/src/FluentNHibernate/Cfg/MappingConfiguration.cs +++ b/src/FluentNHibernate/Cfg/MappingConfiguration.cs @@ -12,6 +12,7 @@ public class MappingConfiguration bool mergeMappings; readonly IDiagnosticLogger logger; PersistenceModel model; + IMappingApplicationStrategy mappingApplicationStrategy; public MappingConfiguration() : this(new NullDiagnosticsLogger()) @@ -35,6 +36,12 @@ public MappingConfiguration UsePersistenceModel(PersistenceModel persistenceMode return this; } + public MappingConfiguration UseMappingApplicationStrategy(IMappingApplicationStrategy mappingApplicationStrategy) + { + this.mappingApplicationStrategy = mappingApplicationStrategy; + return this; + } + /// /// Fluent mappings /// @@ -68,6 +75,15 @@ public bool WasUsed /// /// NHibernate Configuration instance public void Apply(Configuration cfg) + { + Apply(cfg, 1); + } + /// + /// Applies any mappings to the NHibernate Configuration + /// + /// NHibernate Configuration instance + /// the number of threads to use to perform startup + public void Apply(Configuration cfg, int degreeOfParallelism) { foreach (var autoMapping in AutoMappings) autoMapping.SetLogger(logger); @@ -83,7 +99,9 @@ public void Apply(Configuration cfg) HbmMappings.Apply(cfg); FluentMappings.Apply(model); AutoMappings.Apply(cfg, model); - + model.DegreeOfParallelism = degreeOfParallelism; + if (mappingApplicationStrategy != null) + model.MappingApplicationStrategy = mappingApplicationStrategy; model.Configure(cfg); } diff --git a/src/FluentNHibernate/Mapping/TypeMapping.cs.backup b/src/FluentNHibernate/Mapping/TypeMapping.cs.backup new file mode 100644 index 000000000..f85d9bf1c --- /dev/null +++ b/src/FluentNHibernate/Mapping/TypeMapping.cs.backup @@ -0,0 +1,23 @@ +using System; +using System.Collections.Concurrent; + +namespace FluentNHibernate.Mapping +{ + public static class TypeMapping + { + private static readonly ConcurrentDictionary cache = new ConcurrentDictionary(); + + private static string Deduplicate(string str) + { + return cache.GetOrAdd(str, str); + } + + public static string GetTypeString(Type type) + { + if (type.Assembly == typeof(string).Assembly) + return Deduplicate(type.IsGenericType ? type.FullName : type.Name); + + return Deduplicate(type.AssemblyQualifiedName); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/ImportMapping.cs b/src/FluentNHibernate/MappingModel/ImportMapping.cs index 1e3c5038f..84ec893be 100644 --- a/src/FluentNHibernate/MappingModel/ImportMapping.cs +++ b/src/FluentNHibernate/MappingModel/ImportMapping.cs @@ -1,5 +1,7 @@ -using FluentNHibernate.Visitors; using System; +using System.Linq.Expressions; +using FluentNHibernate.Visitors; +using FluentNHibernate.Utils; namespace FluentNHibernate.MappingModel { @@ -61,5 +63,10 @@ protected override void Set(string attribute, int layer, object value) { attributes.Set(attribute, layer, value); } + + public void Set(Expression> expression, int layer, T value) + { + Set(expression.ToMember().Name, layer, value); + } } } \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/MappedMembers.cs b/src/FluentNHibernate/MappingModel/MappedMembers.cs index a386e8154..8ccb832ce 100644 --- a/src/FluentNHibernate/MappingModel/MappedMembers.cs +++ b/src/FluentNHibernate/MappingModel/MappedMembers.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using FluentNHibernate.MappingModel.ClassBased; -using FluentNHibernate.Utils; using FluentNHibernate.Visitors; +using NHibernate.Util; namespace FluentNHibernate.MappingModel { @@ -24,10 +23,14 @@ public enum MappingType { } private readonly List> orderedMappings; + private readonly IReadOnlyDictionary> mappingIndicesByType; public MappedMembers() { orderedMappings = new List>(); + // This has to use a NullableDictionary or (at least) various test cases will fail due to null names on mappings + IDictionary IndexMapGen(MappingType ignored) => new NullableDictionary(); + mappingIndicesByType = Enum.GetValues(typeof(MappingType)).Cast().ToDictionary(m => m, IndexMapGen); } public IEnumerable Properties => orderedMappings.Where(x => x.Item1 == MappingType.Property).Select(x => x.Item2).Cast(); @@ -50,98 +53,90 @@ public MappedMembers() public void AddOrReplaceFilter(FilterMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.Filter, x => x.Name == mapping.Name); + AddOrReplaceMapping(mapping, MappingType.Filter, x => x.Name); } public void AddProperty(PropertyMapping property) { - if (Properties.Any(x => x.Name == property.Name)) - throw new InvalidOperationException("Tried to add property '" + property.Name + "' when already added."); - AddMapping(property, MappingType.Property); + AddMapping(property, MappingType.Property, x => x.Name, + "Tried to add property '" + property.Name + "' when already added."); } public void AddOrReplaceProperty(PropertyMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.Property, x => x.Name == mapping.Name); + AddOrReplaceMapping(mapping, MappingType.Property, x => x.Name); } public void AddCollection(Collections.CollectionMapping collection) { - if (Collections.Any(x => x.Name == collection.Name)) - throw new InvalidOperationException("Tried to add collection '" + collection.Name + "' when already added."); - AddMapping(collection, MappingType.Collection); + AddMapping(collection, MappingType.Collection, x => x.Name, + "Tried to add collection '" + collection.Name + "' when already added."); } public void AddOrReplaceCollection(Collections.CollectionMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.Collection, x => x.Name == mapping.Name); + AddOrReplaceMapping(mapping, MappingType.Collection, x => x.Name); } public void AddReference(ManyToOneMapping manyToOne) { - if (References.Any(x => x.Name == manyToOne.Name)) - throw new InvalidOperationException("Tried to add many-to-one '" + manyToOne.Name + "' when already added."); - AddMapping(manyToOne, MappingType.ManyToOne); + AddMapping(manyToOne, MappingType.ManyToOne, x => x.Name, + "Tried to add many-to-one '" + manyToOne.Name + "' when already added."); } public void AddOrReplaceReference(ManyToOneMapping manyToOne) { - AddOrReplaceMapping(manyToOne, MappingType.ManyToOne, x => x.Name == manyToOne.Name); + AddOrReplaceMapping(manyToOne, MappingType.ManyToOne, x => x.Name); } public void AddComponent(IComponentMapping componentMapping) { - if (Components.Any(x => x.Name == componentMapping.Name)) - throw new InvalidOperationException("Tried to add component '" + componentMapping.Name + "' when already added."); - AddMapping(componentMapping, MappingType.IComponent); + AddMapping(componentMapping, MappingType.IComponent, x => x.Name, + "Tried to add component '" + componentMapping.Name + "' when already added."); } public void AddOrReplaceComponent(IComponentMapping componentMapping) { - AddOrReplaceMapping(componentMapping, MappingType.IComponent, x => x.Name == componentMapping.Name); + AddOrReplaceMapping(componentMapping, MappingType.IComponent, x => x.Name); } public void AddOneToOne(OneToOneMapping mapping) { - if (OneToOnes.Any(x => x.Name == mapping.Name)) - throw new InvalidOperationException("Tried to add one-to-one '" + mapping.Name + "' when already added."); - AddMapping(mapping, MappingType.OneToOne); + AddMapping(mapping, MappingType.OneToOne, x => x.Name, + "Tried to add one-to-one '" + mapping.Name + "' when already added."); } public void AddOrReplaceOneToOne(OneToOneMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.OneToOne, x => x.Name == mapping.Name); + AddOrReplaceMapping(mapping, MappingType.OneToOne, x => x.Name); } public void AddAny(AnyMapping mapping) { - if (Anys.Any(x => x.Name == mapping.Name)) - throw new InvalidOperationException("Tried to add any '" + mapping.Name + "' when already added."); - AddMapping(mapping, MappingType.Any); + AddMapping(mapping, MappingType.Any, x => x.Name, + "Tried to add any '" + mapping.Name + "' when already added."); } public void AddOrReplaceAny(AnyMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.Any, x => x.Name == mapping.Name); + AddOrReplaceMapping(mapping, MappingType.Any, x => x.Name); } public void AddJoin(JoinMapping mapping) { - if (Joins.Any(x => x.TableName == mapping.TableName)) - throw new InvalidOperationException("Tried to add join to table '" + mapping.TableName + "' when already added."); - AddMapping(mapping, MappingType.Join); + AddMapping(mapping, MappingType.Join, x => x.TableName, + "Tried to add join to table '" + mapping.TableName + "' when already added."); } public void AddOrReplaceJoin(JoinMapping mapping) { - AddOrReplaceMapping(mapping, MappingType.Join, x => x.TableName == mapping.TableName); + AddOrReplaceMapping(mapping, MappingType.Join, x => x.TableName); } public void AddFilter(FilterMapping mapping) { - if (Filters.Any(x => x.Name == mapping.Name)) - throw new InvalidOperationException("Tried to add filter with name '" + mapping.Name + "' when already added."); - AddMapping(mapping, MappingType.Filter); + AddMapping(mapping, MappingType.Filter, x => x.Name, + "Tried to add filter with name '" + mapping.Name + "' when already added."); } public virtual void AcceptVisitor(IMappingModelVisitor visitor) @@ -190,7 +185,7 @@ public void Set(string attribute, int layer, object value) public void AddStoredProcedure(StoredProcedureMapping mapping) { - AddMapping(mapping, MappingType.StoredProcedure); + ManageMapping(mapping, MappingType.StoredProcedure, null, true, false, null); } public bool Equals(MappedMembers other) @@ -212,19 +207,37 @@ public override bool Equals(object obj) return orderedMappings.GetHashCode(); } - private void AddMapping(TMapping mapping, MappingType mappingType) where TMapping : IMapping { - orderedMappings.Add(Tuple.Create(mappingType, (IMapping)mapping)); + private void AddMapping(TMapping mapping, MappingType mappingType, Func keyMapper, string badDupeMsg) + where TMapping : IMapping + { + ManageMapping(mapping, mappingType, keyMapper, false, false, badDupeMsg); } - private void AddOrReplaceMapping(TMapping mapping, MappingType mappingType, Predicate matchPredicate) { - var newMapping = Tuple.Create(mappingType, (IMapping)mapping); - var index = orderedMappings.FindIndex(x => x.Item1 == mappingType && matchPredicate((TMapping)x.Item2)); - if (index >= 0) - orderedMappings[index] = newMapping; - else - orderedMappings.Add(newMapping); + private void AddOrReplaceMapping(TMapping mapping, MappingType mappingType, Func keyMapper) where TMapping : IMapping + { + ManageMapping(mapping, mappingType, keyMapper, false, true, null); } + private void ManageMapping(TMapping mapping, MappingType mappingType, Func keyMapper, bool allowDupes, bool allowReplace, + string badDupeMsg) where TMapping : IMapping + { + var newTuple = Tuple.Create(mappingType, (IMapping)mapping); + if (allowDupes) { + orderedMappings.Add(newTuple); + // Types that allow duplicates don't have index tracking + } else { + var key = keyMapper(mapping); + var mappingIndices = mappingIndicesByType[mappingType]; + if (!mappingIndices.ContainsKey(key)) + { + orderedMappings.Add(newTuple); + mappingIndices[key] = orderedMappings.Count - 1; + } + else if (allowReplace) + orderedMappings[mappingIndices[key]] = newTuple; + else + throw new InvalidOperationException(badDupeMsg); + } + } } } - diff --git a/src/FluentNHibernate/MappingModel/NaturalIdMapping.cs b/src/FluentNHibernate/MappingModel/NaturalIdMapping.cs index 32be03e05..f719f84ce 100644 --- a/src/FluentNHibernate/MappingModel/NaturalIdMapping.cs +++ b/src/FluentNHibernate/MappingModel/NaturalIdMapping.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq.Expressions; +using FluentNHibernate.Utils; using FluentNHibernate.Visitors; namespace FluentNHibernate.MappingModel @@ -64,5 +66,9 @@ protected override void Set(string attribute, int layer, object value) { attributes.Set(attribute, layer, value); } + public void Set(Expression> expression, int layer, T value) + { + Set(expression.ToMember().Name, layer, value); + } } } diff --git a/src/FluentNHibernate/MappingModel/Output/EnumBiDictionary.cs b/src/FluentNHibernate/MappingModel/Output/EnumBiDictionary.cs new file mode 100644 index 000000000..c4d23936b --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/EnumBiDictionary.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace FluentNHibernate.MappingModel.Output +{ + public class EnumBiDictionary + where E : Enum + { + private readonly IReadOnlyDictionary valueToMember; + private readonly IReadOnlyDictionary memberToValue; + + public EnumBiDictionary(Func enumToValueMapper) + { + valueToMember = Enum.GetValues(typeof(E)) + .Cast() + .ToDictionary(enumToValueMapper); + memberToValue = valueToMember.ToDictionary(pair => pair.Value, pair => pair.Key); + } + + public EnumBiDictionary(IReadOnlyDictionary enumToValueDict) + { + valueToMember = enumToValueDict.ToDictionary(pair => pair.Value, pair => pair.Key); // Obtain this by inverting the input dictionary + memberToValue = valueToMember.ToDictionary(pair => pair.Value, pair => pair.Key); // Invert the inversion (we could also just copy it, but this is more consistent) + } + + public V this [E enumMember] + { + get { return memberToValue[enumMember]; } + } + + public E this [V value] + { + get { return valueToMember[value]; } + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmAnyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmAnyConverter.cs new file mode 100644 index 000000000..5fae49265 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmAnyConverter.cs @@ -0,0 +1,61 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmAnyConverter : HbmConverterBase + { + private HbmAny hbmAny; + + public HbmAnyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmAny Convert(AnyMapping anyMapping) + { + anyMapping.AcceptVisitor(this); + return hbmAny; + } + + public override void ProcessAny(AnyMapping anyMapping) + { + hbmAny = new HbmAny(); + + if (anyMapping.IsSpecified("Access")) + hbmAny.access = anyMapping.Access; + + if (anyMapping.IsSpecified("Cascade")) + hbmAny.cascade = anyMapping.Cascade; + + if (anyMapping.IsSpecified("IdType")) + hbmAny.idtype = anyMapping.IdType; + + if (anyMapping.IsSpecified("Insert")) + hbmAny.insert = anyMapping.Insert; + + if (anyMapping.IsSpecified("MetaType")) + hbmAny.metatype = anyMapping.MetaType.ToString(); + + if (anyMapping.IsSpecified("Name")) + hbmAny.name = anyMapping.Name; + + if (anyMapping.IsSpecified("Update")) + hbmAny.update = anyMapping.Update; + + if (anyMapping.IsSpecified("Lazy")) + hbmAny.lazy = anyMapping.Lazy; + + if (anyMapping.IsSpecified("OptimisticLock")) + hbmAny.optimisticlock = anyMapping.OptimisticLock; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmAny.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + + public override void Visit(MetaValueMapping metaValueMapping) + { + AddToNullableArray(ref hbmAny.metavalue, ConvertFluentSubobjectToHibernateNative(metaValueMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmArrayConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmArrayConverter.cs new file mode 100644 index 000000000..daba33b87 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmArrayConverter.cs @@ -0,0 +1,159 @@ +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmArrayConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmArray hbmArray; + + public HbmArrayConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmArray Convert(CollectionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmArray; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + hbmArray = new HbmArray(); + + #region Base collection attributes + + // Because the target Hbm* classes do not have a 'base' class that we can target, there isn't any straightforward + // way to make this code reusable, despite being "effectively identical" (apart from the target type) across all + // of the collection types. + + if (collectionMapping.IsSpecified("Access")) + hbmArray.access = collectionMapping.Access; + + bool batchsizeSpecified = collectionMapping.IsSpecified("BatchSize"); + hbmArray.batchsizeSpecified = batchsizeSpecified; + if (batchsizeSpecified) + hbmArray.batchsize = collectionMapping.BatchSize; + + if (collectionMapping.IsSpecified("Cascade")) + hbmArray.cascade = collectionMapping.Cascade; + + if (collectionMapping.IsSpecified("Check")) + hbmArray.check = collectionMapping.Check; + + if (collectionMapping.IsSpecified("CollectionType") && collectionMapping.CollectionType != TypeReference.Empty) + hbmArray.collectiontype = collectionMapping.CollectionType.ToString(); + + bool fetchSpecified = collectionMapping.IsSpecified("Fetch"); + hbmArray.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmArray.fetch = LookupEnumValueIn(fetchDict, collectionMapping.Fetch); + + // HbmArray, unlike HbmList, doesn't support the generic attribute + /* + bool genericSpecified = collectionMapping.IsSpecified("Generic"); + hbmArray.genericSpecified = genericSpecified; + if (genericSpecified) + hbmArray.generic = collectionMapping.Generic; + */ + + if (collectionMapping.IsSpecified("Inverse")) + hbmArray.inverse = collectionMapping.Inverse; + + // HbmArray, unlike HbmList, doesn't support the lazy attribute + /* + bool lazySpecified = collectionMapping.IsSpecified("Lazy"); + hbmArray.lazySpecified = lazySpecified; + if (lazySpecified) + hbmArray.lazy = LookupEnumValueIn(FluentHbmLazyBiDict, collectionMapping.Lazy); + */ + + if (collectionMapping.IsSpecified("Name")) + hbmArray.name = collectionMapping.Name; + + if (collectionMapping.IsSpecified("OptimisticLock")) + hbmArray.optimisticlock = collectionMapping.OptimisticLock; + + if (collectionMapping.IsSpecified("Persister")) + hbmArray.persister = collectionMapping.Persister.ToString(); + + if (collectionMapping.IsSpecified("Schema")) + hbmArray.schema = collectionMapping.Schema; + + if (collectionMapping.IsSpecified("TableName")) + hbmArray.table = collectionMapping.TableName; + + if (collectionMapping.IsSpecified("Where")) + hbmArray.where = collectionMapping.Where; + + if (collectionMapping.IsSpecified("Subselect")) + hbmArray.subselect = collectionMapping.Subselect.ToHbmSubselect(); + + if (collectionMapping.IsSpecified("Mutable")) + hbmArray.mutable = collectionMapping.Mutable; + + #endregion Base collection attributes + + #region Type-specific collection attributes + + // No type-specific attributes for this type + + #endregion Type-specific collection attributes + } + + #region Base collection visitors + + public override void Visit(KeyMapping keyMapping) + { + hbmArray.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmArray.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ICollectionRelationshipMapping collectionRelationshipMapping) + { + // HbmArray.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + // (ManyToMany and OneToMany are implementations of ICollectionRelationshipMapping, and there is no mapping that lines up with ManyToAny) + hbmArray.Item1 = ConvertFluentSubobjectToHibernateNative(collectionRelationshipMapping); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // HbmArray.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmArray.Item1 = ConvertFluentSubobjectToHibernateNative(compositeElementMapping); + } + + public override void Visit(ElementMapping elementMapping) + { + // HbmArray.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmArray.Item1 = ConvertFluentSubobjectToHibernateNative(elementMapping); + } + + // HbmArray, unlike HbmList, doesn't support filters + /* + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmArray.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + */ + + #endregion Base collection visitors + + #region Type-specific collection visitors + + public override void Visit(IIndexMapping indexMapping) + { + // HbmArray.Item is Index / ArrayIndex + // (Index is an implementation of IIndexMapping, while ArrayIndex does not have a fluent mapping yet) + hbmArray.Item = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + + #endregion Type-specific collection visitors + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmBagConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmBagConverter.cs new file mode 100644 index 000000000..7ee33d7f2 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmBagConverter.cs @@ -0,0 +1,147 @@ +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.MappingModel.Output.HbmCollectionConverter; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmBagConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmBag hbmBag; + + public HbmBagConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmBag Convert(CollectionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmBag; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + hbmBag = new HbmBag(); + + #region Base collection attributes + + // Because the target Hbm* classes do not have a 'base' class that we can target, there isn't any straightforward + // way to make this code reusable, despite being "effectively identical" (apart from the target type) across all + // of the collection types. + + if (collectionMapping.IsSpecified("Access")) + hbmBag.access = collectionMapping.Access; + + bool batchsizeSpecified = collectionMapping.IsSpecified("BatchSize"); + hbmBag.batchsizeSpecified = batchsizeSpecified; + if (batchsizeSpecified) + hbmBag.batchsize = collectionMapping.BatchSize; + + if (collectionMapping.IsSpecified("Cascade")) + hbmBag.cascade = collectionMapping.Cascade; + + if (collectionMapping.IsSpecified("Check")) + hbmBag.check = collectionMapping.Check; + + if (collectionMapping.IsSpecified("CollectionType") && collectionMapping.CollectionType != TypeReference.Empty) + hbmBag.collectiontype = collectionMapping.CollectionType.ToString(); + + bool fetchSpecified = collectionMapping.IsSpecified("Fetch"); + hbmBag.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmBag.fetch = LookupEnumValueIn(fetchDict, collectionMapping.Fetch); + + bool genericSpecified = collectionMapping.IsSpecified("Generic"); + hbmBag.genericSpecified = genericSpecified; + if (genericSpecified) + hbmBag.generic = collectionMapping.Generic; + + if (collectionMapping.IsSpecified("Inverse")) + hbmBag.inverse = collectionMapping.Inverse; + + bool lazySpecified = collectionMapping.IsSpecified("Lazy"); + hbmBag.lazySpecified = lazySpecified; + if (lazySpecified) + hbmBag.lazy = LookupEnumValueIn(FluentHbmLazyBiDict, collectionMapping.Lazy); + + if (collectionMapping.IsSpecified("Name")) + hbmBag.name = collectionMapping.Name; + + if (collectionMapping.IsSpecified("OptimisticLock")) + hbmBag.optimisticlock = collectionMapping.OptimisticLock; + + if (collectionMapping.IsSpecified("Persister")) + hbmBag.persister = collectionMapping.Persister.ToString(); + + if (collectionMapping.IsSpecified("Schema")) + hbmBag.schema = collectionMapping.Schema; + + if (collectionMapping.IsSpecified("TableName")) + hbmBag.table = collectionMapping.TableName; + + if (collectionMapping.IsSpecified("Where")) + hbmBag.where = collectionMapping.Where; + + if (collectionMapping.IsSpecified("Subselect")) + hbmBag.subselect = collectionMapping.Subselect.ToHbmSubselect(); + + if (collectionMapping.IsSpecified("Mutable")) + hbmBag.mutable = collectionMapping.Mutable; + + #endregion Base collection attributes + + #region Type-specific collection attributes + + if (collectionMapping.IsSpecified("OrderBy")) + hbmBag.orderby = collectionMapping.OrderBy; + + #endregion Type-specific collection attributes + } + + #region Base collection visitors + + public override void Visit(KeyMapping keyMapping) + { + hbmBag.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmBag.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ICollectionRelationshipMapping collectionRelationshipMapping) + { + // HbmBag.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + // (ManyToMany and OneToMany are implementations of ICollectionRelationshipMapping, and there is no mapping that lines up with ManyToAny) + hbmBag.Item = ConvertFluentSubobjectToHibernateNative(collectionRelationshipMapping); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // HbmBag.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmBag.Item = ConvertFluentSubobjectToHibernateNative(compositeElementMapping); + } + + public override void Visit(ElementMapping elementMapping) + { + // HbmBag.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmBag.Item = ConvertFluentSubobjectToHibernateNative(elementMapping); + } + + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmBag.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + + #endregion Base collection visitors + + #region Type-specific collection visitors + + // No type-specific visitors for this type + + #endregion Type-specific collection visitors + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmBasicSubclassConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmBasicSubclassConverter.cs new file mode 100644 index 000000000..034542d52 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmBasicSubclassConverter.cs @@ -0,0 +1,148 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmBasicSubclassConverter : HbmConverterBase + { + private HbmSubclass hbmSubclass; + + public HbmBasicSubclassConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmSubclass Convert(SubclassMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmSubclass; + } + + public override void ProcessSubclass(SubclassMapping subclassMapping) + { + hbmSubclass = new HbmSubclass(); + + if (subclassMapping.IsSpecified("Name")) + hbmSubclass.name = subclassMapping.Name; + + if (subclassMapping.IsSpecified("Proxy")) + hbmSubclass.proxy = subclassMapping.Proxy; + + bool lazySpecified = subclassMapping.IsSpecified("Lazy"); + hbmSubclass.lazySpecified = lazySpecified; + if (lazySpecified) + hbmSubclass.lazy = subclassMapping.Lazy; + + if (subclassMapping.IsSpecified("DynamicUpdate")) + hbmSubclass.dynamicupdate = subclassMapping.DynamicUpdate; + + if (subclassMapping.IsSpecified("DynamicInsert")) + hbmSubclass.dynamicinsert = subclassMapping.DynamicInsert; + + if (subclassMapping.IsSpecified("SelectBeforeUpdate")) + hbmSubclass.selectbeforeupdate = subclassMapping.SelectBeforeUpdate; + + bool abstractSpecified = subclassMapping.IsSpecified("Abstract"); + hbmSubclass.abstractSpecified = abstractSpecified; + if (abstractSpecified) + hbmSubclass.@abstract = subclassMapping.Abstract; + + if (subclassMapping.IsSpecified("EntityName")) + hbmSubclass.entityname = subclassMapping.EntityName; + + if (subclassMapping.IsSpecified("BatchSize")) + hbmSubclass.batchsize = subclassMapping.BatchSize.ToString(); + + if (subclassMapping.IsSpecified("DiscriminatorValue")) + hbmSubclass.discriminatorvalue = subclassMapping.DiscriminatorValue.ToString(); + } + + #region Methods paralleling XmlSubclassWriter + + public override void Visit(SubclassMapping subclassMapping) + { + var subType = subclassMapping.SubclassType; + if (subType == SubclassType.Subclass) + { + AddToNullableArray(ref hbmSubclass.subclass1, ConvertFluentSubobjectToHibernateNative(subclassMapping)); + } + else + { + throw new NotSupportedException(string.Format("Cannot mix subclass types (subclass type {0} not supported within subclass type {1})", subType, SubclassType.Subclass)); + } + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + public override void Visit(JoinMapping joinMapping) + { + // HbmSubclass.Join is Joins (but nothing else) + AddToNullableArray(ref hbmSubclass.join, ConvertFluentSubobjectToHibernateNative(joinMapping)); + } + + #endregion Methods paralleling XmlSubclassWriter + + #region Methods paralleling XmlClassWriterBase + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmSubclass.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + + public override void Visit(StoredProcedureMapping storedProcedureMapping) + { + var spType = storedProcedureMapping.SPType; + var sprocSql = ConvertFluentSubobjectToHibernateNative(storedProcedureMapping); + switch (spType) + { + case "sql-insert": + hbmSubclass.sqlinsert = sprocSql; + break; + case "sql-update": + hbmSubclass.sqlupdate = sprocSql; + break; + case "sql-delete": + hbmSubclass.sqldelete = sprocSql; + break; + default: + throw new NotSupportedException(string.Format("Stored procedure type {0} is not supported", spType)); + } + } + + #endregion Methods paralleling XmlClassWriterBase + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmCacheConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmCacheConverter.cs new file mode 100644 index 000000000..67372d668 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmCacheConverter.cs @@ -0,0 +1,39 @@ +using System.Linq; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmCacheConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary usageDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary includeDict = new XmlLinkedEnumBiDictionary(); + + private HbmCache hbmCache; + + public HbmCacheConverter() : base(null) + { + } + + public override HbmCache Convert(CacheMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmCache; + } + + public override void ProcessCache(CacheMapping cacheMapping) + { + hbmCache = new HbmCache(); + + if (cacheMapping.IsSpecified("Region")) + hbmCache.region = cacheMapping.Region; + + if (cacheMapping.IsSpecified("Usage")) + hbmCache.usage = LookupEnumValueIn(usageDict, cacheMapping.Usage); + + if (cacheMapping.IsSpecified("Include")) + hbmCache.include = LookupEnumValueIn(includeDict, cacheMapping.Include); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmClassConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmClassConverter.cs new file mode 100644 index 000000000..fbce7f67b --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmClassConverter.cs @@ -0,0 +1,215 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmClassConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary polyDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary optLockDict = new XmlLinkedEnumBiDictionary(); + + private HbmClass hbmClass; + + public HbmClassConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmClass Convert(ClassMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmClass; + } + + public override void ProcessClass(ClassMapping classMapping) + { + hbmClass = new HbmClass(); + + bool batchSizeSpecified = classMapping.IsSpecified("BatchSize"); + hbmClass.batchsizeSpecified = batchSizeSpecified; + if (batchSizeSpecified) + hbmClass.batchsize = classMapping.BatchSize; + + if (classMapping.IsSpecified("DiscriminatorValue")) + hbmClass.discriminatorvalue = classMapping.DiscriminatorValue.ToString(); + + if (classMapping.IsSpecified("DynamicInsert")) + hbmClass.dynamicinsert = classMapping.DynamicInsert; + + if (classMapping.IsSpecified("DynamicUpdate")) + hbmClass.dynamicupdate = classMapping.DynamicUpdate; + + if (classMapping.IsSpecified("Lazy")) + hbmClass.lazy = classMapping.Lazy; + + if (classMapping.IsSpecified("Schema")) + hbmClass.schema = classMapping.Schema; + + if (classMapping.IsSpecified("Mutable")) + hbmClass.mutable = classMapping.Mutable; + + if (classMapping.IsSpecified("Polymorphism")) + hbmClass.polymorphism = LookupEnumValueIn(polyDict, classMapping.Polymorphism); + + if (classMapping.IsSpecified("Persister")) + hbmClass.persister = classMapping.Persister; + + if (classMapping.IsSpecified("Where")) + hbmClass.where = classMapping.Where; + + if (classMapping.IsSpecified("OptimisticLock")) + hbmClass.optimisticlock = LookupEnumValueIn(optLockDict, classMapping.OptimisticLock); + + if (classMapping.IsSpecified("Check")) + hbmClass.check = classMapping.Check; + + if (classMapping.IsSpecified("Name")) + hbmClass.name = classMapping.Name; + + if (classMapping.IsSpecified("TableName")) + hbmClass.table = classMapping.TableName; + + if (classMapping.IsSpecified("Proxy")) + hbmClass.proxy = classMapping.Proxy; + + if (classMapping.IsSpecified("SelectBeforeUpdate")) + hbmClass.selectbeforeupdate = classMapping.SelectBeforeUpdate; + + bool abstractSpecified = classMapping.IsSpecified("Abstract"); + hbmClass.abstractSpecified = abstractSpecified; + if (abstractSpecified) + hbmClass.@abstract = classMapping.Abstract; + + if (classMapping.IsSpecified("Subselect")) + hbmClass.subselect = classMapping.Subselect.ToHbmSubselect(); + + if (classMapping.IsSpecified("SchemaAction")) + hbmClass.schemaaction = classMapping.SchemaAction; + + if (classMapping.IsSpecified("EntityName")) + hbmClass.entityname = classMapping.EntityName; + } + + #region Methods paralleling XmlClassWriter + + public override void Visit(DiscriminatorMapping discriminatorMapping) + { + hbmClass.discriminator = ConvertFluentSubobjectToHibernateNative(discriminatorMapping); + } + + public override void Visit(SubclassMapping subclassMapping) + { + // HbmClass.Items1 is Join / JoinedSubclass / Subclass / UnionSubclass (joined and union subclasses are refinements of SubclassMapping) + AddToNullableArray(ref hbmClass.Items1, ConvertFluentSubobjectToHibernateNative(subclassMapping)); + } + + public override void Visit(JoinMapping joinMapping) + { + // HbmClass.Items1 is Join / JoinedSubclass / Subclass / UnionSubclass + AddToNullableArray(ref hbmClass.Items1, ConvertFluentSubobjectToHibernateNative(joinMapping)); + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + public override void Visit(IIdentityMapping identityMapping) + { + // HbmClass.Item is Id / CompositeId (IdMapping and CompositeIdMapping are implementations of IIdentityMapping) + hbmClass.Item = ConvertFluentSubobjectToHibernateNative(identityMapping); + } + + public override void Visit(NaturalIdMapping naturalIdMapping) + { + hbmClass.naturalid = ConvertFluentSubobjectToHibernateNative(naturalIdMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmClass.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmClass.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + + public override void Visit(TuplizerMapping tuplizerMapping) + { + AddToNullableArray(ref hbmClass.tuplizer, ConvertFluentSubobjectToHibernateNative(tuplizerMapping)); + } + + #endregion Methods paralleling XmlClassWriter + + #region Methods paralleling XmlClassWriterBase + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(VersionMapping versionMapping) + { + // HbmClass.Item1 is Timestamp / Version + hbmClass.Item1 = ConvertFluentSubobjectToHibernateNative(versionMapping); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + // Visit(ManyToOneMapping) is defined for both XmlClassWriter and XmlClassWriterBase, so the implementation for this class lives in the "parallel to XmlClassWriter" section + + public override void Visit(AnyMapping anyMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmClass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmClass.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + + public override void Visit(StoredProcedureMapping storedProcedureMapping) + { + var spType = storedProcedureMapping.SPType; + var sprocSql = ConvertFluentSubobjectToHibernateNative(storedProcedureMapping); + switch (spType) + { + case "sql-insert": + hbmClass.sqlinsert = sprocSql; + break; + case "sql-update": + hbmClass.sqlupdate = sprocSql; + break; + case "sql-delete": + hbmClass.sqldelete = sprocSql; + break; + default: + throw new NotSupportedException(string.Format("Stored procedure type {0} is not supported", spType)); + } + } + + #endregion Methods paralleling XmlClassWriterBase + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmCollectionConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmCollectionConverter.cs new file mode 100644 index 000000000..3925563c9 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmCollectionConverter.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmCollectionConverter : HbmConverterBase + { + public static readonly EnumBiDictionary FluentHbmLazyBiDict = new EnumBiDictionary( + new Dictionary() { + { HbmCollectionLazy.True, Lazy.True }, + { HbmCollectionLazy.False, Lazy.False }, + { HbmCollectionLazy.Extra, Lazy.Extra }, + } + ); + + private object hbmCollection; + + public HbmCollectionConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(CollectionMapping collectionMapping) + { + collectionMapping.AcceptVisitor(this); + return hbmCollection; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + // C# doesn't allow wildcard generic types, so we have to do the assignment inline for each case, + // rather than being able to simply assign the converter and then use it at the end. + switch (collectionMapping.Collection) + { + case Collection.Array: + hbmCollection = ConvertFluentSubobjectToHibernateNative(collectionMapping); + break; + case Collection.Bag: + hbmCollection = ConvertFluentSubobjectToHibernateNative(collectionMapping); + break; + case Collection.List: + hbmCollection = ConvertFluentSubobjectToHibernateNative(collectionMapping); + break; + case Collection.Map: + hbmCollection = ConvertFluentSubobjectToHibernateNative(collectionMapping); + break; + case Collection.Set: + hbmCollection = ConvertFluentSubobjectToHibernateNative(collectionMapping); + break; + default: + throw new InvalidOperationException("Unrecognised collection type " + collectionMapping.Collection); + } + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmCollectionRelationshipConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmCollectionRelationshipConverter.cs new file mode 100644 index 000000000..5c9cf9682 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmCollectionRelationshipConverter.cs @@ -0,0 +1,30 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmCollectionRelationshipConverter : HbmConverterBase + { + private object hbmCollectionRelationship; + + public HbmCollectionRelationshipConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(ICollectionRelationshipMapping collectionRelationshipMapping) + { + collectionRelationshipMapping.AcceptVisitor(this); + return hbmCollectionRelationship; + } + + public override void ProcessOneToMany(OneToManyMapping oneToManyMapping) + { + hbmCollectionRelationship = ConvertFluentSubobjectToHibernateNative(oneToManyMapping); + } + + public override void ProcessManyToMany(ManyToManyMapping manyToManyMapping) + { + hbmCollectionRelationship = ConvertFluentSubobjectToHibernateNative(manyToManyMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmColumnConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmColumnConverter.cs new file mode 100644 index 000000000..91d2eb239 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmColumnConverter.cs @@ -0,0 +1,61 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmColumnConverter : HbmConverterBase + { + private HbmColumn hbmColumn; + + public HbmColumnConverter() : base(null) + { + } + + public override HbmColumn Convert(ColumnMapping columnMapping) + { + columnMapping.AcceptVisitor(this); + return hbmColumn; + } + + public override void ProcessColumn(ColumnMapping columnMapping) + { + hbmColumn = new HbmColumn(); + + if (columnMapping.IsSpecified("Name")) + hbmColumn.name = columnMapping.Name; + + if (columnMapping.IsSpecified("Check")) + hbmColumn.check = columnMapping.Check; + + if (columnMapping.IsSpecified("Length")) + hbmColumn.length = columnMapping.Length.ToString(); + + if (columnMapping.IsSpecified("Index")) + hbmColumn.index = columnMapping.Index; + + bool notNullSpecified = columnMapping.IsSpecified("NotNull"); + hbmColumn.notnullSpecified = notNullSpecified; + if (notNullSpecified) + hbmColumn.notnull = columnMapping.NotNull; + + if (columnMapping.IsSpecified("SqlType")) + hbmColumn.sqltype = columnMapping.SqlType; + + bool uniqueSpecified = columnMapping.IsSpecified("Unique"); + hbmColumn.uniqueSpecified = uniqueSpecified; + if (uniqueSpecified) + hbmColumn.unique = columnMapping.Unique; + + if (columnMapping.IsSpecified("UniqueKey")) + hbmColumn.uniquekey = columnMapping.UniqueKey; + + if (columnMapping.IsSpecified("Precision")) + hbmColumn.precision = columnMapping.Precision.ToString(); + + if (columnMapping.IsSpecified("Scale")) + hbmColumn.scale = columnMapping.Scale.ToString(); + + if (columnMapping.IsSpecified("Default")) + hbmColumn.@default = columnMapping.Default; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmComponentBasedConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmComponentBasedConverter.cs new file mode 100644 index 000000000..cfe11634d --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmComponentBasedConverter.cs @@ -0,0 +1,55 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmReferenceComponentConverter : HbmConverterBase + { + public HbmReferenceComponentConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + // Use a specialized handoff to mimic the XML side, due to complexities of how visitors are handled by ReferenceComponentMapping + public override object Convert(ReferenceComponentMapping referenceComponentMapping) + { + return ConvertFluentSubobjectToHibernateNative(referenceComponentMapping.MergedModel); + } + } + + public class HbmComponentBasedConverter : HbmConverterBase + { + private object hbm; + + public HbmComponentBasedConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(IComponentMapping componentMapping) + { + componentMapping.AcceptVisitor(this); + return hbm; + } + + public override void ProcessComponent(ComponentMapping componentMapping) + { + bool dummy = false; + if (dummy) + throw new NotSupportedException(String.Format("In normal component processing for {0}", componentMapping)); + var compType = componentMapping.ComponentType; + if (compType == ComponentType.Component) + { + hbm = ConvertFluentSubobjectToHibernateNative(componentMapping); + } + else if (compType == ComponentType.DynamicComponent) + { + hbm = ConvertFluentSubobjectToHibernateNative(componentMapping); + } + else + { + throw new NotSupportedException(string.Format("Component type {0} is not supported", compType)); + } + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmComponentConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmComponentConverter.cs new file mode 100644 index 000000000..3834f5b92 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmComponentConverter.cs @@ -0,0 +1,92 @@ +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmComponentConverter : HbmConverterBase + { + private HbmComponent hbmComponent; + + public HbmComponentConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmComponent Convert(ComponentMapping componentMapping) + { + componentMapping.AcceptVisitor(this); + return hbmComponent; + } + + public override void ProcessComponent(ComponentMapping componentMapping) + { + hbmComponent = new HbmComponent(); + + if (componentMapping.IsSpecified("Access")) + hbmComponent.access = componentMapping.Access; + + if (componentMapping.IsSpecified("Class")) + hbmComponent.@class = componentMapping.Class.ToString(); + + if (componentMapping.IsSpecified("Insert")) + hbmComponent.insert = componentMapping.Insert; + + if (componentMapping.IsSpecified("Name")) + hbmComponent.name = componentMapping.Name; + + if (componentMapping.IsSpecified("Update")) + hbmComponent.update = componentMapping.Update; + + if (componentMapping.IsSpecified("Lazy")) + hbmComponent.lazy = componentMapping.Lazy; + + if (componentMapping.IsSpecified("OptimisticLock")) + hbmComponent.optimisticlock = componentMapping.OptimisticLock; + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + public override void Visit(ParentMapping parentMapping) + { + hbmComponent.parent = ConvertFluentSubobjectToHibernateNative(parentMapping); + } + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmComponent.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmComponent.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmCompositeElementConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmCompositeElementConverter.cs new file mode 100644 index 000000000..cee99f19c --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmCompositeElementConverter.cs @@ -0,0 +1,50 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmCompositeElementConverter : HbmConverterBase + { + private HbmCompositeElement hbmCompositeElement; + + public HbmCompositeElementConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmCompositeElement Convert(CompositeElementMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmCompositeElement; + } + + public override void ProcessCompositeElement(CompositeElementMapping compositeElementMapping) + { + hbmCompositeElement = new HbmCompositeElement(); + + if (compositeElementMapping.IsSpecified("Class")) + hbmCompositeElement.@class = compositeElementMapping.Class.ToString(); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // AddCompositeElement on the mapping can only ever take a nested composite element, so this is safe + NestedCompositeElementMapping nestedCompositeElementMapping = compositeElementMapping as NestedCompositeElementMapping; + AddToNullableArray(ref hbmCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(nestedCompositeElementMapping)); + } + + public override void Visit(PropertyMapping propertyMapping) + { + AddToNullableArray(ref hbmCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + AddToNullableArray(ref hbmCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(ParentMapping parentMapping) + { + hbmCompositeElement.parent = ConvertFluentSubobjectToHibernateNative(parentMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmCompositeIdConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmCompositeIdConverter.cs new file mode 100644 index 000000000..8d1eaf057 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmCompositeIdConverter.cs @@ -0,0 +1,52 @@ +using FluentNHibernate.MappingModel.Identity; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmCompositeIdConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary unsavedDict = new XmlLinkedEnumBiDictionary(); + + private HbmCompositeId hbmCompositeId; + + public HbmCompositeIdConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmCompositeId Convert(CompositeIdMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmCompositeId; + } + + public override void ProcessCompositeId(CompositeIdMapping compositeIdMapping) + { + hbmCompositeId = new HbmCompositeId(); + + if (compositeIdMapping.IsSpecified("Access")) + hbmCompositeId.access = compositeIdMapping.Access; + + if (compositeIdMapping.IsSpecified("Name")) + hbmCompositeId.name = compositeIdMapping.Name; + + if (compositeIdMapping.IsSpecified("Class")) + hbmCompositeId.@class = compositeIdMapping.Class.ToString(); + + if (compositeIdMapping.IsSpecified("Mapped")) + hbmCompositeId.mapped = compositeIdMapping.Mapped; + + if (compositeIdMapping.IsSpecified("UnsavedValue")) + hbmCompositeId.unsavedvalue = LookupEnumValueIn(unsavedDict, compositeIdMapping.UnsavedValue); + } + + public override void Visit(KeyPropertyMapping keyPropertyMapping) + { + AddToNullableArray(ref hbmCompositeId.Items, ConvertFluentSubobjectToHibernateNative(keyPropertyMapping)); + } + + public override void Visit(KeyManyToOneMapping keyManyToOneMapping) + { + AddToNullableArray(ref hbmCompositeId.Items, ConvertFluentSubobjectToHibernateNative(keyManyToOneMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmConverterBase.cs b/src/FluentNHibernate/MappingModel/Output/HbmConverterBase.cs new file mode 100644 index 000000000..fed15f016 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmConverterBase.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using FluentNHibernate.Visitors; + +namespace FluentNHibernate.MappingModel.Output +{ + public abstract class HbmConverterBase : NullMappingModelVisitor, IHbmConverter + { + private readonly IHbmConverterServiceLocator serviceLocator; + + protected HbmConverterBase(IHbmConverterServiceLocator serviceLocator) + { + this.serviceLocator = serviceLocator; + } + + public abstract H Convert(F mapping); + + protected HSub ConvertFluentSubobjectToHibernateNative(FSub fluentMapping) + { + var converter = serviceLocator.GetConverter(); + return converter.Convert(fluentMapping); + } + + protected void AddToNullableArray(ref T[] nullableArray, T item) + { + if (nullableArray == null) + nullableArray = new T[0]; + Array.Resize(ref nullableArray, nullableArray.Length + 1); + nullableArray[nullableArray.Length - 1] = item; + } + + protected E LookupEnumValueIn(EnumBiDictionary enumDict, V key) + where E : System.Enum + { + try + { + return enumDict[key]; + } + catch (KeyNotFoundException keyEx) + { + throw new NotSupportedException(String.Format("{0} is not a recognized value for {1}", key, typeof(E).Name), keyEx); + } + } + + protected E LookupEnumValueIn(XmlLinkedEnumBiDictionary enumDict, String key) + where E : System.Enum + { + return LookupEnumValueIn(enumDict, key); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmConverterContainer.cs b/src/FluentNHibernate/MappingModel/Output/HbmConverterContainer.cs new file mode 100644 index 000000000..9c9d13930 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmConverterContainer.cs @@ -0,0 +1,194 @@ +using System; +using FluentNHibernate.Infrastructure; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.MappingModel.Identity; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmConverterContainer : Container + { + public HbmConverterContainer() + { + Register(c => + new HbmConverterServiceLocator(this)); + + RegisterConverter(c => + new HbmHibernateMappingConverter(c.Resolve())); + + RegisterConverter(c => + new HbmClassConverter(c.Resolve())); + + RegisterConverter(c => + new HbmImportConverter()); + + RegisterConverter(c => + new HbmPropertyConverter(c.Resolve())); + + RegisterIdConverters(); + RegisterComponentConverters(); + + RegisterConverter(c => + new HbmNaturalIdConverter(c.Resolve())); + + RegisterConverter(c => + new HbmColumnConverter()); + + RegisterConverter(c => + new HbmJoinConverter(c.Resolve())); + + RegisterConverter(c => + new HbmDiscriminatorConverter(c.Resolve())); + + RegisterConverter(c => + new HbmKeyConverter(c.Resolve())); + + RegisterConverter(c => + new HbmParentConverter()); + + RegisterConverter(c => + new HbmCompositeElementConverter(c.Resolve())); + + RegisterConverter(c => + new HbmNestedCompositeElementConverter(c.Resolve())); + + RegisterConverter(c => + new HbmVersionConverter(c.Resolve())); + + RegisterConverter(c => + new HbmCacheConverter()); + + RegisterConverter(c => + new HbmOneToOneConverter()); + + RegisterCollectionConverters(); + + RegisterConverter(c => + new HbmIndexBasedConverter(c.Resolve())); + + RegisterConverter(c => + new HbmIndexConverter(c.Resolve())); + + RegisterConverter(c => + new HbmListIndexConverter(c.Resolve())); + + RegisterConverter(c => + new HbmIndexManyToManyConverter(c.Resolve())); + + RegisterConverter(c => + new HbmElementConverter(c.Resolve())); + + RegisterConverter(c => + new HbmOneToManyConverter()); + + RegisterConverter(c => + new HbmAnyConverter(c.Resolve())); + + RegisterConverter(c => + new HbmMetaValueConverter()); + + // collection relationships + RegisterConverter(c => + new HbmCollectionRelationshipConverter(c.Resolve())); + + RegisterConverter(c => + new HbmManyToOneConverter(c.Resolve())); + + RegisterConverter(c => + new HbmManyToManyConverter(c.Resolve())); + + RegisterSubclassConverters(); + + RegisterConverter(c => + new HbmFilterConverter()); + + RegisterConverter(c => + new HbmFilterDefinitionConverter()); + + RegisterConverter(c => + new HbmStoredProcedureConverter()); + + RegisterConverter(c => + new HbmTuplizerConverter()); + } + + private void RegisterIdConverters() + { + RegisterConverter(c => + new HbmIdentityBasedConverter(c.Resolve())); + + RegisterConverter(c => + new HbmIdConverter(c.Resolve())); + + RegisterConverter(c => + new HbmCompositeIdConverter(c.Resolve())); + + RegisterConverter(c => + new HbmGeneratorConverter()); + + RegisterConverter(c => + new HbmKeyPropertyConverter(c.Resolve())); + + RegisterConverter(c => + new HbmKeyManyToOneConverter(c.Resolve())); + } + + private void RegisterCollectionConverters() + { + RegisterConverter(c => + new HbmCollectionConverter(c.Resolve())); + + RegisterConverter(c => + new HbmArrayConverter(c.Resolve())); + + RegisterConverter(c => + new HbmBagConverter(c.Resolve())); + + RegisterConverter(c => + new HbmListConverter(c.Resolve())); + + RegisterConverter(c => + new HbmMapConverter(c.Resolve())); + + RegisterConverter(c => + new HbmSetConverter(c.Resolve())); + } + + private void RegisterSubclassConverters() + { + RegisterConverter(c => + new HbmSubclassConverter(c.Resolve())); + + RegisterConverter(c => + new HbmBasicSubclassConverter(c.Resolve())); + + RegisterConverter(c => + new HbmJoinedSubclassConverter(c.Resolve())); + + RegisterConverter(c => + new HbmUnionSubclassConverter(c.Resolve())); + } + + private void RegisterComponentConverters() + { + RegisterConverter(c => + new HbmComponentBasedConverter(c.Resolve())); + + RegisterConverter(c => + new HbmReferenceComponentConverter(c.Resolve())); + + RegisterConverter(c => + new HbmComponentConverter(c.Resolve())); + + RegisterConverter(c => + new HbmDynamicComponentConverter(c.Resolve())); + } + + private void RegisterConverter(Func instantiate) + { + Register>(instantiate); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmConverterFactory.cs b/src/FluentNHibernate/MappingModel/Output/HbmConverterFactory.cs new file mode 100644 index 000000000..d1b8c0a40 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmConverterFactory.cs @@ -0,0 +1,15 @@ +using FluentNHibernate.Infrastructure; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public static class HbmConverterFactory + { + private static readonly Container Container = new HbmConverterContainer(); + + public static IHbmConverter CreateHibernateMappingConverter() + { + return Container.Resolve>(); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmConverterServiceLocator.cs b/src/FluentNHibernate/MappingModel/Output/HbmConverterServiceLocator.cs new file mode 100644 index 000000000..c049380b3 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmConverterServiceLocator.cs @@ -0,0 +1,19 @@ +using FluentNHibernate.Infrastructure; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmConverterServiceLocator : IHbmConverterServiceLocator + { + private readonly Container container; + + public HbmConverterServiceLocator(Container container) + { + this.container = container; + } + + public IHbmConverter GetConverter() + { + return container.Resolve>(); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmDiscriminatorConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmDiscriminatorConverter.cs new file mode 100644 index 000000000..48d0af3ac --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmDiscriminatorConverter.cs @@ -0,0 +1,42 @@ +using FluentNHibernate.Mapping; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmDiscriminatorConverter : HbmConverterBase + { + private HbmDiscriminator hbmDiscriminator; + + public HbmDiscriminatorConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmDiscriminator Convert(DiscriminatorMapping discriminatorMapping) + { + discriminatorMapping.AcceptVisitor(this); + return hbmDiscriminator; + } + + public override void ProcessDiscriminator(DiscriminatorMapping discriminatorMapping) + { + hbmDiscriminator = new HbmDiscriminator(); + + if (discriminatorMapping.IsSpecified("Type")) + hbmDiscriminator.type = TypeMapping.GetTypeString(discriminatorMapping.Type.GetUnderlyingSystemType()); + + if (discriminatorMapping.IsSpecified("Force")) + hbmDiscriminator.force = discriminatorMapping.Force; + + if (discriminatorMapping.IsSpecified("Formula")) + hbmDiscriminator.formula = discriminatorMapping.Formula; + + if (discriminatorMapping.IsSpecified("Insert")) + hbmDiscriminator.insert = discriminatorMapping.Insert; + } + + public override void Visit(ColumnMapping columnMapping) + { + hbmDiscriminator.Item = ConvertFluentSubobjectToHibernateNative(columnMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmDynamicComponentConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmDynamicComponentConverter.cs new file mode 100644 index 000000000..f9dfc8fa1 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmDynamicComponentConverter.cs @@ -0,0 +1,81 @@ +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmDynamicComponentConverter : HbmConverterBase + { + private HbmDynamicComponent hbmDynamicComponent; + + public HbmDynamicComponentConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmDynamicComponent Convert(ComponentMapping dynamicComponentMapping) + { + dynamicComponentMapping.AcceptVisitor(this); + return hbmDynamicComponent; + } + + public override void ProcessComponent(ComponentMapping dynamicComponentMapping) + { + hbmDynamicComponent = new HbmDynamicComponent(); + + if (dynamicComponentMapping.IsSpecified("Access")) + hbmDynamicComponent.access = dynamicComponentMapping.Access; + + if (dynamicComponentMapping.IsSpecified("Insert")) + hbmDynamicComponent.insert = dynamicComponentMapping.Insert; + + if (dynamicComponentMapping.IsSpecified("Name")) + hbmDynamicComponent.name = dynamicComponentMapping.Name; + + if (dynamicComponentMapping.IsSpecified("Update")) + hbmDynamicComponent.update = dynamicComponentMapping.Update; + + if (dynamicComponentMapping.IsSpecified("OptimisticLock")) + hbmDynamicComponent.optimisticlock = dynamicComponentMapping.OptimisticLock; + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + // (DynamicComponentMapping, ExternalDynamicComponentMapping, and ReferenceDynamicComponentMapping are implementations of IDynamicComponentMapping, while + // DynamicDynamicComponentMapping is a refinement of DynamicComponentMapping) + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmDynamicComponent.Items is Any / Array / Bag / Component / DynamicComponent / List / ManyToOne / Map / OneToOne / PrimitiveArray / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmDynamicComponent.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmElementConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmElementConverter.cs new file mode 100644 index 000000000..d6a341263 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmElementConverter.cs @@ -0,0 +1,36 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmElementConverter : HbmConverterBase + { + private HbmElement hbmElement; + + public HbmElementConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmElement Convert(ElementMapping elementMapping) + { + elementMapping.AcceptVisitor(this); + return hbmElement; + } + + public override void ProcessElement(ElementMapping elementMapping) + { + hbmElement = new HbmElement(); + + if (elementMapping.IsSpecified("Type")) + hbmElement.type1 = elementMapping.Type.ToString(); + + if (elementMapping.IsSpecified("Formula")) + hbmElement.formula = elementMapping.Formula; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmElement.Items, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmFilterConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmFilterConverter.cs new file mode 100644 index 000000000..5dd4fa06f --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmFilterConverter.cs @@ -0,0 +1,31 @@ +using System.Linq; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmFilterConverter : HbmConverterBase + { + private HbmFilter hbmFilter; + + public HbmFilterConverter() : base(null) + { + } + + public override HbmFilter Convert(FilterMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmFilter; + } + + public override void ProcessFilter(FilterMapping filterMapping) + { + hbmFilter = new HbmFilter(); + + hbmFilter.name = filterMapping.Name; + + if (!string.IsNullOrEmpty(filterMapping.Condition)) + hbmFilter.condition = filterMapping.Condition; + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmFilterDefinitionConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmFilterDefinitionConverter.cs new file mode 100644 index 000000000..c5ca07eab --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmFilterDefinitionConverter.cs @@ -0,0 +1,34 @@ +using System.Linq; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmFilterDefinitionConverter : HbmConverterBase + { + private HbmFilterDef hbmFilterDef; + + public HbmFilterDefinitionConverter() : base(null) + { + } + + public override HbmFilterDef Convert(FilterDefinitionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmFilterDef; + } + + public override void ProcessFilterDefinition(FilterDefinitionMapping filterDefinitionMapping) + { + hbmFilterDef = new HbmFilterDef(); + + hbmFilterDef.name = filterDefinitionMapping.Name; + + if (!string.IsNullOrEmpty(filterDefinitionMapping.Condition)) + hbmFilterDef.condition = filterDefinitionMapping.Condition; + + if (filterDefinitionMapping.Parameters.Any()) + hbmFilterDef.Items = filterDefinitionMapping.Parameters.Select(paramPair => paramPair.ToHbmFilterParam()).ToArray(); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmGeneratorConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmGeneratorConverter.cs new file mode 100644 index 000000000..08a9b1494 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmGeneratorConverter.cs @@ -0,0 +1,33 @@ +using System.Linq; +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmGeneratorConverter : HbmConverterBase + { + private HbmGenerator hbmGenerator; + + public HbmGeneratorConverter() : base(null) + { + } + + public override HbmGenerator Convert(GeneratorMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmGenerator; + } + + public override void ProcessGenerator(GeneratorMapping generatorMapping) + { + hbmGenerator = new HbmGenerator(); + + if (!string.IsNullOrEmpty(generatorMapping.Class)) + hbmGenerator.@class = generatorMapping.Class; + + if (generatorMapping.Params.Any()) + hbmGenerator.param = generatorMapping.Params.Select(paramPair => paramPair.ToHbmParam()).ToArray(); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmHibernateMappingConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmHibernateMappingConverter.cs new file mode 100644 index 000000000..18aa23991 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmHibernateMappingConverter.cs @@ -0,0 +1,64 @@ +using FluentNHibernate.MappingModel.ClassBased; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmHibernateMappingConverter : HbmConverterBase + { + private HbmMapping hbmMapping; + + public HbmHibernateMappingConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmMapping Convert(HibernateMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmMapping; + } + + public override void ProcessHibernateMapping(HibernateMapping mapping) + { + hbmMapping = new HbmMapping(); + + if (mapping.IsSpecified("DefaultAccess")) + hbmMapping.defaultaccess = mapping.DefaultAccess; + + if (mapping.IsSpecified("AutoImport")) + hbmMapping.autoimport = mapping.AutoImport; + + if (mapping.IsSpecified("Schema")) + hbmMapping.schema = mapping.Schema; + + if (mapping.IsSpecified("DefaultCascade")) + hbmMapping.defaultcascade = mapping.DefaultCascade; + + if (mapping.IsSpecified("DefaultLazy")) + hbmMapping.defaultlazy = mapping.DefaultLazy; + + if (mapping.IsSpecified("Catalog")) + hbmMapping.catalog = mapping.Catalog; + + if (mapping.IsSpecified("Namespace")) + hbmMapping.@namespace = mapping.Namespace; + + if (mapping.IsSpecified("Assembly")) + hbmMapping.assembly = mapping.Assembly; + } + + public override void Visit(ImportMapping importMapping) + { + AddToNullableArray(ref hbmMapping.import, ConvertFluentSubobjectToHibernateNative(importMapping)); + } + + public override void Visit(ClassMapping classMapping) + { + AddToNullableArray(ref hbmMapping.Items, ConvertFluentSubobjectToHibernateNative(classMapping)); + } + + public override void Visit(FilterDefinitionMapping filterDefinitionMapping) + { + AddToNullableArray(ref hbmMapping.filterdef, ConvertFluentSubobjectToHibernateNative(filterDefinitionMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmIdConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmIdConverter.cs new file mode 100644 index 000000000..7b990a7bf --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmIdConverter.cs @@ -0,0 +1,47 @@ +using FluentNHibernate.MappingModel.Identity; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmIdConverter : HbmConverterBase + { + private HbmId hbmId; + + public HbmIdConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmId Convert(IdMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmId; + } + + public override void ProcessId(IdMapping idMapping) + { + hbmId = new HbmId(); + + if (idMapping.IsSpecified("Access")) + hbmId.access = idMapping.Access; + + if (idMapping.IsSpecified("Name")) + hbmId.name = idMapping.Name; + + if (idMapping.IsSpecified("Type")) + hbmId.type1 = idMapping.Type.ToString(); + + if (idMapping.IsSpecified("UnsavedValue")) + hbmId.unsavedvalue = idMapping.UnsavedValue; + } + + public override void Visit(GeneratorMapping generatorMapping) + { + hbmId.generator = ConvertFluentSubobjectToHibernateNative(generatorMapping); + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmId.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmIdentityBasedConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmIdentityBasedConverter.cs new file mode 100644 index 000000000..20e40934c --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmIdentityBasedConverter.cs @@ -0,0 +1,31 @@ +using FluentNHibernate.MappingModel.Identity; +using FluentNHibernate.Visitors; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmIdentityBasedConverter : HbmConverterBase + { + private object hbm; + + public HbmIdentityBasedConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(IIdentityMapping identityMapping) + { + identityMapping.AcceptVisitor(this); + return hbm; + } + + public override void ProcessId(IdMapping idMapping) + { + hbm = ConvertFluentSubobjectToHibernateNative(idMapping); + } + + public override void ProcessCompositeId(CompositeIdMapping compositeIdMapping) + { + hbm = ConvertFluentSubobjectToHibernateNative(compositeIdMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmImportConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmImportConverter.cs new file mode 100644 index 000000000..cc10d54aa --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmImportConverter.cs @@ -0,0 +1,30 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmImportConverter : HbmConverterBase + { + private HbmImport hbmImport; + + public HbmImportConverter() : base(null) + { + } + + public override HbmImport Convert(ImportMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmImport; + } + + public override void ProcessImport(ImportMapping mapping) + { + hbmImport = new HbmImport(); + + if (mapping.IsSpecified("Class")) + hbmImport.@class = mapping.Class.ToString(); + + if (mapping.IsSpecified("Rename")) + hbmImport.rename = mapping.Rename; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmIndexBasedConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmIndexBasedConverter.cs new file mode 100644 index 000000000..e7c17c7f4 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmIndexBasedConverter.cs @@ -0,0 +1,37 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmIndexBasedConverter : HbmConverterBase + { + private object hbm; + + public HbmIndexBasedConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(IIndexMapping indexMapping) + { + indexMapping.AcceptVisitor(this); + return hbm; + } + + public override void ProcessIndex(IndexMapping indexMapping) + { + if (indexMapping.IsSpecified("Offset")) + { + hbm = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + else + { + hbm = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + } + + public override void ProcessIndex(IndexManyToManyMapping indexMapping) + { + hbm = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmIndexConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmIndexConverter.cs new file mode 100644 index 000000000..4f1b1e37f --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmIndexConverter.cs @@ -0,0 +1,33 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmIndexConverter : HbmConverterBase + { + private HbmIndex hbmIndex; + + public HbmIndexConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmIndex Convert(IndexMapping indexMapping) + { + indexMapping.AcceptVisitor(this); + return hbmIndex; + } + + public override void ProcessIndex(IndexMapping indexMapping) + { + hbmIndex = new HbmIndex(); + + if (indexMapping.IsSpecified("Type")) + hbmIndex.type = indexMapping.Type.ToString(); + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmIndex.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmIndexManyToManyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmIndexManyToManyConverter.cs new file mode 100644 index 000000000..8159db1b6 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmIndexManyToManyConverter.cs @@ -0,0 +1,39 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmIndexManyToManyConverter : HbmConverterBase + { + private HbmIndexManyToMany hbmIndexManyToMany; + + public HbmIndexManyToManyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmIndexManyToMany Convert(IndexManyToManyMapping indexManyToManyMapping) + { + indexManyToManyMapping.AcceptVisitor(this); + return hbmIndexManyToMany; + } + + public override void ProcessIndex(IndexManyToManyMapping indexManyToManyMapping) + { + hbmIndexManyToMany = new HbmIndexManyToMany(); + + if (indexManyToManyMapping.IsSpecified("Class")) + hbmIndexManyToMany.@class = indexManyToManyMapping.Class.ToString(); + + if (indexManyToManyMapping.IsSpecified("ForeignKey")) + hbmIndexManyToMany.foreignkey = indexManyToManyMapping.ForeignKey; + + if (indexManyToManyMapping.IsSpecified("EntityName")) + hbmIndexManyToMany.entityname = indexManyToManyMapping.EntityName; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmIndexManyToMany.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmJoinConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmJoinConverter.cs new file mode 100644 index 000000000..01a592f79 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmJoinConverter.cs @@ -0,0 +1,109 @@ +using System; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmJoinConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmJoin hbmJoin; + + public HbmJoinConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmJoin Convert(JoinMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmJoin; + } + + public override void ProcessJoin(JoinMapping joinMapping) + { + hbmJoin = new HbmJoin(); + + if (joinMapping.IsSpecified("TableName")) + hbmJoin.table = joinMapping.TableName; + + if (joinMapping.IsSpecified("Schema")) + hbmJoin.schema = joinMapping.Schema; + + if (joinMapping.IsSpecified("Fetch")) + hbmJoin.fetch = LookupEnumValueIn(fetchDict, joinMapping.Fetch); + + if (joinMapping.IsSpecified("Catalog")) + hbmJoin.catalog = joinMapping.Catalog; + + if (joinMapping.IsSpecified("Subselect")) + hbmJoin.subselect = joinMapping.Subselect.ToHbmSubselect(); + + if (joinMapping.IsSpecified("Inverse")) + hbmJoin.inverse = joinMapping.Inverse; + + if (joinMapping.IsSpecified("Optional")) + hbmJoin.optional = joinMapping.Optional; + } + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmJoin.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmJoin.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(KeyMapping keyMapping) + { + hbmJoin.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmJoin.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmJoin.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmJoin.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / PrimitiveArray / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmJoin.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmJoin.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / PrimitiveArray / Property / Set + AddToNullableArray(ref hbmJoin.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmJoin.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / PrimitiveArray / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmJoin.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + + public override void Visit(StoredProcedureMapping storedProcedureMapping) + { + var spType = storedProcedureMapping.SPType; + var sprocSql = ConvertFluentSubobjectToHibernateNative(storedProcedureMapping); + switch (spType) + { + case "sql-insert": + hbmJoin.sqlinsert = sprocSql; + break; + case "sql-update": + hbmJoin.sqlupdate = sprocSql; + break; + case "sql-delete": + hbmJoin.sqldelete = sprocSql; + break; + default: + throw new NotSupportedException(string.Format("Stored procedure type {0} is not supported", spType)); + } + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmJoinedSubclassConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmJoinedSubclassConverter.cs new file mode 100644 index 000000000..9f87f72a8 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmJoinedSubclassConverter.cs @@ -0,0 +1,160 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmJoinedSubclassConverter : HbmConverterBase + { + private HbmJoinedSubclass hbmJoinedSubclass; + + public HbmJoinedSubclassConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmJoinedSubclass Convert(SubclassMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmJoinedSubclass; + } + + public override void ProcessSubclass(SubclassMapping subclassMapping) + { + hbmJoinedSubclass = new HbmJoinedSubclass(); + + if (subclassMapping.IsSpecified("Name")) + hbmJoinedSubclass.name = subclassMapping.Name; + + if (subclassMapping.IsSpecified("Proxy")) + hbmJoinedSubclass.proxy = subclassMapping.Proxy; + + bool lazySpecified = subclassMapping.IsSpecified("Lazy"); + hbmJoinedSubclass.lazySpecified = lazySpecified; + if (lazySpecified) + hbmJoinedSubclass.lazy = subclassMapping.Lazy; + + if (subclassMapping.IsSpecified("DynamicUpdate")) + hbmJoinedSubclass.dynamicupdate = subclassMapping.DynamicUpdate; + + if (subclassMapping.IsSpecified("DynamicInsert")) + hbmJoinedSubclass.dynamicinsert = subclassMapping.DynamicInsert; + + if (subclassMapping.IsSpecified("SelectBeforeUpdate")) + hbmJoinedSubclass.selectbeforeupdate = subclassMapping.SelectBeforeUpdate; + + bool abstractSpecified = subclassMapping.IsSpecified("Abstract"); + hbmJoinedSubclass.abstractSpecified = abstractSpecified; + if (abstractSpecified) + hbmJoinedSubclass.@abstract = subclassMapping.Abstract; + + if (subclassMapping.IsSpecified("EntityName")) + hbmJoinedSubclass.entityname = subclassMapping.EntityName; + + if (subclassMapping.IsSpecified("BatchSize")) + hbmJoinedSubclass.batchsize = subclassMapping.BatchSize.ToString(); + + if (subclassMapping.IsSpecified("TableName")) + hbmJoinedSubclass.table = subclassMapping.TableName; + + if (subclassMapping.IsSpecified("Schema")) + hbmJoinedSubclass.schema = subclassMapping.Schema; + + if (subclassMapping.IsSpecified("Check")) + hbmJoinedSubclass.check = subclassMapping.Check; + + if (subclassMapping.IsSpecified("Subselect")) + hbmJoinedSubclass.subselect = subclassMapping.Subselect.ToHbmSubselect(); + + if (subclassMapping.IsSpecified("Persister")) + hbmJoinedSubclass.persister = subclassMapping.Persister.ToString(); + } + + #region Methods paralleling XmlSubclassWriter + + public override void Visit(KeyMapping keyMapping) + { + hbmJoinedSubclass.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(SubclassMapping subclassMapping) + { + var subType = subclassMapping.SubclassType; + if (subType == SubclassType.JoinedSubclass) + { + AddToNullableArray(ref hbmJoinedSubclass.joinedsubclass1, ConvertFluentSubobjectToHibernateNative(subclassMapping)); + } + else + { + throw new NotSupportedException(string.Format("Cannot mix subclass types (subclass type {0} not supported within subclass type {1})", subType, SubclassType.Subclass)); + } + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + #endregion Methods paralleling XmlSubclassWriter + + #region Methods paralleling XmlClassWriterBase + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmJoinedSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmJoinedSubclass.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + + public override void Visit(StoredProcedureMapping storedProcedureMapping) + { + var spType = storedProcedureMapping.SPType; + var sprocSql = ConvertFluentSubobjectToHibernateNative(storedProcedureMapping); + switch (spType) + { + case "sql-insert": + hbmJoinedSubclass.sqlinsert = sprocSql; + break; + case "sql-update": + hbmJoinedSubclass.sqlupdate = sprocSql; + break; + case "sql-delete": + hbmJoinedSubclass.sqldelete = sprocSql; + break; + default: + throw new NotSupportedException(string.Format("Stored procedure type {0} is not supported", spType)); + } + } + + #endregion Methods paralleling XmlClassWriterBase + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmKeyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmKeyConverter.cs new file mode 100644 index 000000000..37a86688a --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmKeyConverter.cs @@ -0,0 +1,55 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmKeyConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary ondeleteDict = new XmlLinkedEnumBiDictionary(); + + private HbmKey hbmKey; + + public HbmKeyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmKey Convert(KeyMapping keyMapping) + { + keyMapping.AcceptVisitor(this); + return hbmKey; + } + + public override void ProcessKey(KeyMapping keyMapping) + { + hbmKey = new HbmKey(); + + if (keyMapping.IsSpecified("ForeignKey")) + hbmKey.foreignkey = keyMapping.ForeignKey; + + if (keyMapping.IsSpecified("OnDelete")) + hbmKey.ondelete = LookupEnumValueIn(ondeleteDict, keyMapping.OnDelete); + + if (keyMapping.IsSpecified("PropertyRef")) + hbmKey.propertyref = keyMapping.PropertyRef; + + bool notnullSpecified = keyMapping.IsSpecified("NotNull"); + hbmKey.notnullSpecified = notnullSpecified; + if (notnullSpecified) + hbmKey.notnull = keyMapping.NotNull; + + bool updateSpecified = keyMapping.IsSpecified("Update"); + hbmKey.updateSpecified = updateSpecified; + if (updateSpecified) + hbmKey.update = keyMapping.Update; + + bool uniqueSpecified = keyMapping.IsSpecified("Unique"); + hbmKey.uniqueSpecified = uniqueSpecified; + if (uniqueSpecified) + hbmKey.unique = keyMapping.Unique; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmKey.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmKeyManyToOneConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmKeyManyToOneConverter.cs new file mode 100644 index 000000000..00aee7be8 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmKeyManyToOneConverter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using FluentNHibernate.MappingModel.Identity; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmKeyManyToOneConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary notFoundDict = new XmlLinkedEnumBiDictionary(); + + private HbmKeyManyToOne hbmKeyManyToOne; + + public HbmKeyManyToOneConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmKeyManyToOne Convert(KeyManyToOneMapping keyManyToOneMapping) + { + keyManyToOneMapping.AcceptVisitor(this); + return hbmKeyManyToOne; + } + + public override void ProcessKeyManyToOne(KeyManyToOneMapping keyManyToOneMapping) + { + hbmKeyManyToOne = new HbmKeyManyToOne(); + + if (keyManyToOneMapping.IsSpecified("Access")) + hbmKeyManyToOne.access = keyManyToOneMapping.Access; + + if (keyManyToOneMapping.IsSpecified("Name")) + hbmKeyManyToOne.name = keyManyToOneMapping.Name; + + if (keyManyToOneMapping.IsSpecified("Class")) + hbmKeyManyToOne.@class = keyManyToOneMapping.Class.ToString(); + + if (keyManyToOneMapping.IsSpecified("ForeignKey")) + hbmKeyManyToOne.foreignkey = keyManyToOneMapping.ForeignKey; + + bool lazySpecified = keyManyToOneMapping.IsSpecified("Lazy"); + hbmKeyManyToOne.lazySpecified = lazySpecified; + if (lazySpecified) + hbmKeyManyToOne.lazy = keyManyToOneMapping.Lazy ? HbmRestrictedLaziness.Proxy : HbmRestrictedLaziness.False; + + if (keyManyToOneMapping.IsSpecified("NotFound")) + hbmKeyManyToOne.notfound = LookupEnumValueIn(notFoundDict, keyManyToOneMapping.NotFound); + + if (keyManyToOneMapping.IsSpecified("EntityName")) + hbmKeyManyToOne.entityname = keyManyToOneMapping.EntityName; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmKeyManyToOne.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmKeyPropertyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmKeyPropertyConverter.cs new file mode 100644 index 000000000..eea3650fa --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmKeyPropertyConverter.cs @@ -0,0 +1,55 @@ +using System.Linq; +using FluentNHibernate.MappingModel.Identity; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmKeyPropertyConverter : HbmConverterBase + { + private HbmKeyProperty hbmKeyProperty; + + public HbmKeyPropertyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmKeyProperty Convert(KeyPropertyMapping keyPropertyMapping) + { + keyPropertyMapping.AcceptVisitor(this); + return hbmKeyProperty; + } + + public override void ProcessKeyProperty(KeyPropertyMapping keyPropertyMapping) + { + hbmKeyProperty = new HbmKeyProperty(); + + if (keyPropertyMapping.IsSpecified("Name")) + hbmKeyProperty.name = keyPropertyMapping.Name; + + + if (keyPropertyMapping.IsSpecified("Access")) + hbmKeyProperty.access = keyPropertyMapping.Access; + + if (keyPropertyMapping.IsSpecified("Type")) + hbmKeyProperty.type1 = keyPropertyMapping.Type.ToString(); + + if (keyPropertyMapping.IsSpecified("Length")) + { + if (keyPropertyMapping.Columns.Any()) + { + foreach (var columnMapping in keyPropertyMapping.Columns.Where(column => !column.IsSpecified("Length"))) + { + columnMapping.Set(map => map.Length, Layer.Defaults, keyPropertyMapping.Length); + } + } + else + { + hbmKeyProperty.length = keyPropertyMapping.Length.ToString(); + } + } + } + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmKeyProperty.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmListConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmListConverter.cs new file mode 100644 index 000000000..e4fd2cd2a --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmListConverter.cs @@ -0,0 +1,151 @@ +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.MappingModel.Output.HbmCollectionConverter; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmListConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmList hbmList; + + public HbmListConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmList Convert(CollectionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmList; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + hbmList = new HbmList(); + + #region Base collection attributes + + // Because the target Hbm* classes do not have a 'base' class that we can target, there isn't any straightforward + // way to make this code reusable, despite being "effectively identical" (apart from the target type) across all + // of the collection types. + + if (collectionMapping.IsSpecified("Access")) + hbmList.access = collectionMapping.Access; + + bool batchsizeSpecified = collectionMapping.IsSpecified("BatchSize"); + hbmList.batchsizeSpecified = batchsizeSpecified; + if (batchsizeSpecified) + hbmList.batchsize = collectionMapping.BatchSize; + + if (collectionMapping.IsSpecified("Cascade")) + hbmList.cascade = collectionMapping.Cascade; + + if (collectionMapping.IsSpecified("Check")) + hbmList.check = collectionMapping.Check; + + if (collectionMapping.IsSpecified("CollectionType") && collectionMapping.CollectionType != TypeReference.Empty) + hbmList.collectiontype = collectionMapping.CollectionType.ToString(); + + bool fetchSpecified = collectionMapping.IsSpecified("Fetch"); + hbmList.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmList.fetch = LookupEnumValueIn(fetchDict, collectionMapping.Fetch); + + bool genericSpecified = collectionMapping.IsSpecified("Generic"); + hbmList.genericSpecified = genericSpecified; + if (genericSpecified) + hbmList.generic = collectionMapping.Generic; + + if (collectionMapping.IsSpecified("Inverse")) + hbmList.inverse = collectionMapping.Inverse; + + bool lazySpecified = collectionMapping.IsSpecified("Lazy"); + hbmList.lazySpecified = lazySpecified; + if (lazySpecified) + hbmList.lazy = LookupEnumValueIn(FluentHbmLazyBiDict, collectionMapping.Lazy); + + if (collectionMapping.IsSpecified("Name")) + hbmList.name = collectionMapping.Name; + + if (collectionMapping.IsSpecified("OptimisticLock")) + hbmList.optimisticlock = collectionMapping.OptimisticLock; + + if (collectionMapping.IsSpecified("Persister")) + hbmList.persister = collectionMapping.Persister.ToString(); + + if (collectionMapping.IsSpecified("Schema")) + hbmList.schema = collectionMapping.Schema; + + if (collectionMapping.IsSpecified("TableName")) + hbmList.table = collectionMapping.TableName; + + if (collectionMapping.IsSpecified("Where")) + hbmList.where = collectionMapping.Where; + + if (collectionMapping.IsSpecified("Subselect")) + hbmList.subselect = collectionMapping.Subselect.ToHbmSubselect(); + + if (collectionMapping.IsSpecified("Mutable")) + hbmList.mutable = collectionMapping.Mutable; + + #endregion Base collection attributes + + #region Type-specific collection attributes + + // No type-specific attributes for this type + + #endregion Type-specific collection attributes + } + + #region Base collection visitors + + public override void Visit(KeyMapping keyMapping) + { + hbmList.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmList.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ICollectionRelationshipMapping collectionRelationshipMapping) + { + // HbmList.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + // (ManyToMany and OneToMany are implementations of ICollectionRelationshipMapping, and there is no mapping that lines up with ManyToAny) + hbmList.Item1 = ConvertFluentSubobjectToHibernateNative(collectionRelationshipMapping); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // HbmList.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmList.Item1 = ConvertFluentSubobjectToHibernateNative(compositeElementMapping); + } + + public override void Visit(ElementMapping elementMapping) + { + // HbmList.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmList.Item1 = ConvertFluentSubobjectToHibernateNative(elementMapping); + } + + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmList.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + + #endregion Base collection visitors + + #region Type-specific collection visitors + + public override void Visit(IIndexMapping indexMapping) + { + // HbmList.Item is Index / ListIndex + // (Index is an implementation of IIndexMapping, while ListIndex does not have a fluent mapping yet) + hbmList.Item = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + + #endregion Type-specific collection visitors + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmListIndexConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmListIndexConverter.cs new file mode 100644 index 000000000..8a6b3b045 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmListIndexConverter.cs @@ -0,0 +1,32 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmListIndexConverter : HbmConverterBase + { + private HbmListIndex hbmListIndex; + + public HbmListIndexConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmListIndex Convert(IndexMapping indexMapping) + { + indexMapping.AcceptVisitor(this); + return hbmListIndex; + } + + public override void ProcessIndex(IndexMapping indexMapping) + { + hbmListIndex = new HbmListIndex(); + + hbmListIndex.@base = indexMapping.Offset.ToString(); + } + + public override void Visit(ColumnMapping columnMapping) + { + hbmListIndex.column = ConvertFluentSubobjectToHibernateNative(columnMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmManyToManyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmManyToManyConverter.cs new file mode 100644 index 000000000..8a75bf5c9 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmManyToManyConverter.cs @@ -0,0 +1,64 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmManyToManyConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary notFoundDict = new XmlLinkedEnumBiDictionary(); + + private HbmManyToMany hbmManyToMany; + + public HbmManyToManyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmManyToMany Convert(ManyToManyMapping manyToManyMapping) + { + manyToManyMapping.AcceptVisitor(this); + return hbmManyToMany; + } + + public override void ProcessManyToMany(ManyToManyMapping manyToManyMapping) + { + hbmManyToMany = new HbmManyToMany(); + + if (manyToManyMapping.IsSpecified("Class")) + hbmManyToMany.@class = manyToManyMapping.Class.ToString(); + + bool fetchSpecified = manyToManyMapping.IsSpecified("Fetch"); + hbmManyToMany.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmManyToMany.fetch = LookupEnumValueIn(fetchDict, manyToManyMapping.Fetch); + + if (manyToManyMapping.IsSpecified("ForeignKey")) + hbmManyToMany.foreignkey = manyToManyMapping.ForeignKey; + + if (manyToManyMapping.IsSpecified("ChildPropertyRef")) + hbmManyToMany.propertyref = manyToManyMapping.ChildPropertyRef; + + bool lazySpecified = manyToManyMapping.IsSpecified("Lazy"); + hbmManyToMany.lazySpecified = lazySpecified; + if (lazySpecified) + hbmManyToMany.lazy = manyToManyMapping.Lazy ? HbmRestrictedLaziness.Proxy : HbmRestrictedLaziness.False; + + if (manyToManyMapping.IsSpecified("NotFound")) + hbmManyToMany.notfound = LookupEnumValueIn(notFoundDict, manyToManyMapping.NotFound); + + if (manyToManyMapping.IsSpecified("Where")) + hbmManyToMany.where = manyToManyMapping.Where; + + if (manyToManyMapping.IsSpecified("EntityName")) + hbmManyToMany.entityname = manyToManyMapping.EntityName; + + if (manyToManyMapping.IsSpecified("OrderBy")) + hbmManyToMany.orderby = manyToManyMapping.OrderBy; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmManyToMany.Items, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmManyToOneConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmManyToOneConverter.cs new file mode 100644 index 000000000..f0a95ed95 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmManyToOneConverter.cs @@ -0,0 +1,79 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmManyToOneConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary lazyDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary notFoundDict = new XmlLinkedEnumBiDictionary(); + + private HbmManyToOne hbmManyToOne; + + public HbmManyToOneConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmManyToOne Convert(ManyToOneMapping manyToOneMapping) + { + manyToOneMapping.AcceptVisitor(this); + return hbmManyToOne; + } + + public override void ProcessManyToOne(ManyToOneMapping manyToOneMapping) + { + hbmManyToOne = new HbmManyToOne(); + + if (manyToOneMapping.IsSpecified("Access")) + hbmManyToOne.access = manyToOneMapping.Access; + + if (manyToOneMapping.IsSpecified("Cascade")) + hbmManyToOne.cascade = manyToOneMapping.Cascade; + + if (manyToOneMapping.IsSpecified("Class")) + hbmManyToOne.@class = manyToOneMapping.Class.ToString(); + + bool fetchSpecified = manyToOneMapping.IsSpecified("Fetch"); + hbmManyToOne.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmManyToOne.fetch = LookupEnumValueIn(fetchDict, manyToOneMapping.Fetch); + + if (manyToOneMapping.IsSpecified("ForeignKey")) + hbmManyToOne.foreignkey = manyToOneMapping.ForeignKey; + + if (manyToOneMapping.IsSpecified("Insert")) + hbmManyToOne.insert = manyToOneMapping.Insert; + + bool lazySpecified = manyToOneMapping.IsSpecified("Lazy"); + hbmManyToOne.lazySpecified = lazySpecified; + if (lazySpecified) + hbmManyToOne.lazy = LookupEnumValueIn(lazyDict, manyToOneMapping.Lazy); + + if (manyToOneMapping.IsSpecified("Name")) + hbmManyToOne.name = manyToOneMapping.Name; + + if (manyToOneMapping.IsSpecified("NotFound")) + hbmManyToOne.notfound = LookupEnumValueIn(notFoundDict, manyToOneMapping.NotFound); + + if (manyToOneMapping.IsSpecified("Formula")) + hbmManyToOne.formula = manyToOneMapping.Formula; + + if (manyToOneMapping.IsSpecified("PropertyRef")) + hbmManyToOne.propertyref = manyToOneMapping.PropertyRef; + + if (manyToOneMapping.IsSpecified("Update")) + hbmManyToOne.update = manyToOneMapping.Update; + + if (manyToOneMapping.IsSpecified("EntityName")) + hbmManyToOne.entityname = manyToOneMapping.EntityName; + + if (manyToOneMapping.IsSpecified("OptimisticLock")) + hbmManyToOne.optimisticlock = manyToOneMapping.OptimisticLock; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmManyToOne.Items, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmMapConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmMapConverter.cs new file mode 100644 index 000000000..d6f938841 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmMapConverter.cs @@ -0,0 +1,155 @@ +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.MappingModel.Output.HbmCollectionConverter; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmMapConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmMap hbmMap; + + public HbmMapConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmMap Convert(CollectionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmMap; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + hbmMap = new HbmMap(); + + #region Base collection attributes + + // Because the target Hbm* classes do not have a 'base' class that we can target, there isn't any straightforward + // way to make this code reusable, despite being "effectively identical" (apart from the target type) across all + // of the collection types. + + if (collectionMapping.IsSpecified("Access")) + hbmMap.access = collectionMapping.Access; + + bool batchsizeSpecified = collectionMapping.IsSpecified("BatchSize"); + hbmMap.batchsizeSpecified = batchsizeSpecified; + if (batchsizeSpecified) + hbmMap.batchsize = collectionMapping.BatchSize; + + if (collectionMapping.IsSpecified("Cascade")) + hbmMap.cascade = collectionMapping.Cascade; + + if (collectionMapping.IsSpecified("Check")) + hbmMap.check = collectionMapping.Check; + + if (collectionMapping.IsSpecified("CollectionType") && collectionMapping.CollectionType != TypeReference.Empty) + hbmMap.collectiontype = collectionMapping.CollectionType.ToString(); + + bool fetchSpecified = collectionMapping.IsSpecified("Fetch"); + hbmMap.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmMap.fetch = LookupEnumValueIn(fetchDict, collectionMapping.Fetch); + + bool genericSpecified = collectionMapping.IsSpecified("Generic"); + hbmMap.genericSpecified = genericSpecified; + if (genericSpecified) + hbmMap.generic = collectionMapping.Generic; + + if (collectionMapping.IsSpecified("Inverse")) + hbmMap.inverse = collectionMapping.Inverse; + + bool lazySpecified = collectionMapping.IsSpecified("Lazy"); + hbmMap.lazySpecified = lazySpecified; + if (lazySpecified) + hbmMap.lazy = LookupEnumValueIn(FluentHbmLazyBiDict, collectionMapping.Lazy); + + if (collectionMapping.IsSpecified("Name")) + hbmMap.name = collectionMapping.Name; + + if (collectionMapping.IsSpecified("OptimisticLock")) + hbmMap.optimisticlock = collectionMapping.OptimisticLock; + + if (collectionMapping.IsSpecified("Persister")) + hbmMap.persister = collectionMapping.Persister.ToString(); + + if (collectionMapping.IsSpecified("Schema")) + hbmMap.schema = collectionMapping.Schema; + + if (collectionMapping.IsSpecified("TableName")) + hbmMap.table = collectionMapping.TableName; + + if (collectionMapping.IsSpecified("Where")) + hbmMap.where = collectionMapping.Where; + + if (collectionMapping.IsSpecified("Subselect")) + hbmMap.subselect = collectionMapping.Subselect.ToHbmSubselect(); + + if (collectionMapping.IsSpecified("Mutable")) + hbmMap.mutable = collectionMapping.Mutable; + + #endregion Base collection attributes + + #region Type-specific collection attributes + + if (collectionMapping.IsSpecified("OrderBy")) + hbmMap.orderby = collectionMapping.OrderBy; + + if (collectionMapping.IsSpecified("Sort")) + hbmMap.sort = collectionMapping.Sort; + + #endregion Type-specific collection attributes + } + + #region Base collection visitors + + public override void Visit(KeyMapping keyMapping) + { + hbmMap.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmMap.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ICollectionRelationshipMapping collectionRelationshipMapping) + { + // HbmMap.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + // (ManyToMany and OneToMany are implementations of ICollectionRelationshipMapping, and there is no mapping that lines up with ManyToAny) + hbmMap.Item1 = ConvertFluentSubobjectToHibernateNative(collectionRelationshipMapping); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // HbmMap.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmMap.Item1 = ConvertFluentSubobjectToHibernateNative(compositeElementMapping); + } + + public override void Visit(ElementMapping elementMapping) + { + // HbmMap.Item1 is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmMap.Item1 = ConvertFluentSubobjectToHibernateNative(elementMapping); + } + + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmMap.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + + #endregion Base collection visitors + + #region Type-specific collection visitors + + public override void Visit(IIndexMapping indexMapping) + { + // HbmMap.Item is CompositeIndex / CompositeMapKey / Index / IndexManyToAny / IndexManyToMany / MapKey / MapKeyManyToMany + // (Index and IndexManyToMany are implementations of IIndexMapping, while none of the others have fluent mappings yet) + hbmMap.Item = ConvertFluentSubobjectToHibernateNative(indexMapping); + } + + #endregion Type-specific collection visitors + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmMappingApplicationStrategy.cs b/src/FluentNHibernate/MappingModel/Output/HbmMappingApplicationStrategy.cs new file mode 100644 index 000000000..eaf218b50 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmMappingApplicationStrategy.cs @@ -0,0 +1,25 @@ +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + /// + /// A mapping application strategy which utilizes for translation. + /// + public class HbmMappingApplicationStrategy : MappingApplicationStrategyBase + { + public HbmMappingApplicationStrategy() + { + } + + protected override HbmMapping ToIntermediateForm(HibernateMapping mapping) + { + return new MappingHbmConverter().Convert(mapping); + } + + protected override void ApplyIntermediateFormToConfiguration(HbmMapping intermediateForm, Configuration cfg) + { + cfg.AddDeserializedMapping(intermediateForm, "(Direct)"); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmMetaValueConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmMetaValueConverter.cs new file mode 100644 index 000000000..a7a7df07e --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmMetaValueConverter.cs @@ -0,0 +1,30 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmMetaValueConverter : HbmConverterBase + { + private HbmMetaValue hbmMetaValue; + + public HbmMetaValueConverter() : base(null) + { + } + + public override HbmMetaValue Convert(MetaValueMapping metaValueMapping) + { + metaValueMapping.AcceptVisitor(this); + return hbmMetaValue; + } + + public override void ProcessMetaValue(MetaValueMapping metaValueMapping) + { + hbmMetaValue = new HbmMetaValue(); + + if (metaValueMapping.IsSpecified("Class")) + hbmMetaValue.@class = metaValueMapping.Class.ToString(); + + if (metaValueMapping.IsSpecified("Value")) + hbmMetaValue.value = metaValueMapping.Value; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmNaturalIdConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmNaturalIdConverter.cs new file mode 100644 index 000000000..4497c7318 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmNaturalIdConverter.cs @@ -0,0 +1,37 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmNaturalIdConverter : HbmConverterBase + { + private HbmNaturalId hbmNaturalId; + + public HbmNaturalIdConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmNaturalId Convert(NaturalIdMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmNaturalId; + } + + public override void ProcessNaturalId(NaturalIdMapping naturalIdMapping) + { + hbmNaturalId = new HbmNaturalId(); + + if (naturalIdMapping.IsSpecified("Mutable")) + hbmNaturalId.mutable = naturalIdMapping.Mutable; + } + + public override void Visit(PropertyMapping propertyMapping) + { + AddToNullableArray(ref hbmNaturalId.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + AddToNullableArray(ref hbmNaturalId.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmNestedCompositeElementConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmNestedCompositeElementConverter.cs new file mode 100644 index 000000000..dfadeb8d2 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmNestedCompositeElementConverter.cs @@ -0,0 +1,58 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmNestedCompositeElementConverter : HbmConverterBase + { + private HbmNestedCompositeElement hbmNestedCompositeElement; + + public HbmNestedCompositeElementConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmNestedCompositeElement Convert(NestedCompositeElementMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmNestedCompositeElement; + } + + public override void ProcessCompositeElement(CompositeElementMapping compositeElementMapping) + { + // Should always be true if this converter is being invoked + NestedCompositeElementMapping nestedCompositeElementMapping = compositeElementMapping as NestedCompositeElementMapping; + + hbmNestedCompositeElement = new HbmNestedCompositeElement(); + + if (nestedCompositeElementMapping.IsSpecified("Class")) + hbmNestedCompositeElement.@class = nestedCompositeElementMapping.Class.ToString(); + + hbmNestedCompositeElement.name = nestedCompositeElementMapping.Name; + + if (nestedCompositeElementMapping.IsSpecified("Access")) + hbmNestedCompositeElement.access = nestedCompositeElementMapping.Access; + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // AddCompositeElement on the mapping can only ever take a nested composite element, so this is safe + NestedCompositeElementMapping nestedCompositeElementMapping = compositeElementMapping as NestedCompositeElementMapping; + AddToNullableArray(ref hbmNestedCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(nestedCompositeElementMapping)); + } + + public override void Visit(PropertyMapping propertyMapping) + { + AddToNullableArray(ref hbmNestedCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + AddToNullableArray(ref hbmNestedCompositeElement.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(ParentMapping parentMapping) + { + hbmNestedCompositeElement.parent = ConvertFluentSubobjectToHibernateNative(parentMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmOneToManyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmOneToManyConverter.cs new file mode 100644 index 000000000..1412392f8 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmOneToManyConverter.cs @@ -0,0 +1,36 @@ +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmOneToManyConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary notFoundDict = new XmlLinkedEnumBiDictionary(); + + private HbmOneToMany hbmOneToMany; + + public HbmOneToManyConverter() : base(null) + { + } + + public override HbmOneToMany Convert(OneToManyMapping oneToManyMapping) + { + oneToManyMapping.AcceptVisitor(this); + return hbmOneToMany; + } + + public override void ProcessOneToMany(OneToManyMapping oneToManyMapping) + { + hbmOneToMany = new HbmOneToMany(); + + if (oneToManyMapping.IsSpecified("Class")) + hbmOneToMany.@class = oneToManyMapping.Class.ToString(); + + if (oneToManyMapping.IsSpecified("NotFound")) + hbmOneToMany.notfound = LookupEnumValueIn(notFoundDict, oneToManyMapping.NotFound); + + if (oneToManyMapping.IsSpecified("EntityName")) + hbmOneToMany.entityname = oneToManyMapping.EntityName; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmOneToOneConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmOneToOneConverter.cs new file mode 100644 index 000000000..e3696db7d --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmOneToOneConverter.cs @@ -0,0 +1,61 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmOneToOneConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + private static readonly XmlLinkedEnumBiDictionary lazyDict = new XmlLinkedEnumBiDictionary(); + + private HbmOneToOne hbmOneToOne; + + public HbmOneToOneConverter() : base(null) + { + } + + public override HbmOneToOne Convert(OneToOneMapping oneToOneMapping) + { + oneToOneMapping.AcceptVisitor(this); + return hbmOneToOne; + } + + public override void ProcessOneToOne(OneToOneMapping oneToOneMapping) + { + hbmOneToOne = new HbmOneToOne(); + + if (oneToOneMapping.IsSpecified("Access")) + hbmOneToOne.access = oneToOneMapping.Access; + + if (oneToOneMapping.IsSpecified("Cascade")) + hbmOneToOne.cascade = oneToOneMapping.Cascade; + + if (oneToOneMapping.IsSpecified("Class")) + hbmOneToOne.@class = oneToOneMapping.Class.ToString(); + + if (oneToOneMapping.IsSpecified("Constrained")) + hbmOneToOne.constrained = oneToOneMapping.Constrained; + + bool fetchSpecified = oneToOneMapping.IsSpecified("Fetch"); + hbmOneToOne.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmOneToOne.fetch = LookupEnumValueIn(fetchDict, oneToOneMapping.Fetch); + + if (oneToOneMapping.IsSpecified("ForeignKey")) + hbmOneToOne.foreignkey = oneToOneMapping.ForeignKey; + + bool lazySpecified = oneToOneMapping.IsSpecified("Lazy"); + hbmOneToOne.lazySpecified = lazySpecified; + if (lazySpecified) + hbmOneToOne.lazy = LookupEnumValueIn(lazyDict, oneToOneMapping.Lazy); + + if (oneToOneMapping.IsSpecified("Name")) + hbmOneToOne.name = oneToOneMapping.Name; + + if (oneToOneMapping.IsSpecified("PropertyRef")) + hbmOneToOne.propertyref = oneToOneMapping.PropertyRef; + + if (oneToOneMapping.IsSpecified("EntityName")) + hbmOneToOne.entityname = oneToOneMapping.EntityName; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmParentConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmParentConverter.cs new file mode 100644 index 000000000..a5972a910 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmParentConverter.cs @@ -0,0 +1,30 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmParentConverter : HbmConverterBase + { + private HbmParent hbmParent; + + public HbmParentConverter() : base(null) + { + } + + public override HbmParent Convert(ParentMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmParent; + } + + public override void ProcessParent(ParentMapping parentMapping) + { + hbmParent = new HbmParent(); + + if (parentMapping.IsSpecified("Name")) + hbmParent.name = parentMapping.Name; + + if (parentMapping.IsSpecified("Access")) + hbmParent.access = parentMapping.Access; + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmPropertyConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmPropertyConverter.cs new file mode 100644 index 000000000..e7bd5d13f --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmPropertyConverter.cs @@ -0,0 +1,62 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmPropertyConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary genDict = new XmlLinkedEnumBiDictionary(); + + private HbmProperty hbmProperty; + + public HbmPropertyConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmProperty Convert(PropertyMapping propertyMapping) + { + propertyMapping.AcceptVisitor(this); + return hbmProperty; + } + + public override void ProcessProperty(PropertyMapping propertyMapping) + { + hbmProperty = new HbmProperty(); + + if (propertyMapping.IsSpecified("Access")) + hbmProperty.access = propertyMapping.Access; + + if (propertyMapping.IsSpecified("Generated")) + hbmProperty.generated = LookupEnumValueIn(genDict, propertyMapping.Generated); + + if (propertyMapping.IsSpecified("Name")) + hbmProperty.name = propertyMapping.Name; + + if (propertyMapping.IsSpecified("OptimisticLock")) + hbmProperty.optimisticlock = propertyMapping.OptimisticLock; + + bool insertSpecified = propertyMapping.IsSpecified("Insert"); + hbmProperty.insertSpecified = insertSpecified; + if (insertSpecified) + hbmProperty.insert = propertyMapping.Insert; + + bool updateSpecified = propertyMapping.IsSpecified("Update"); + hbmProperty.updateSpecified = updateSpecified; + if (updateSpecified) + hbmProperty.update = propertyMapping.Update; + + if (propertyMapping.IsSpecified("Formula")) + hbmProperty.formula = propertyMapping.Formula; + + if (propertyMapping.IsSpecified("Type")) + hbmProperty.type1 = propertyMapping.Type.ToString(); + + if (propertyMapping.IsSpecified("Lazy")) + hbmProperty.lazy = propertyMapping.Lazy; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmProperty.Items, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmSetConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmSetConverter.cs new file mode 100644 index 000000000..82addc1c2 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmSetConverter.cs @@ -0,0 +1,150 @@ +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using static FluentNHibernate.MappingModel.Output.HbmCollectionConverter; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmSetConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary fetchDict = new XmlLinkedEnumBiDictionary(); + + private HbmSet hbmSet; + + public HbmSetConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmSet Convert(CollectionMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmSet; + } + + public override void ProcessCollection(CollectionMapping collectionMapping) + { + hbmSet = new HbmSet(); + + #region Base collection attributes + + // Because the target Hbm* classes do not have a 'base' class that we can target, there isn't any straightforward + // way to make this code reusable, despite being "effectively identical" (apart from the target type) across all + // of the collection types. + + if (collectionMapping.IsSpecified("Access")) + hbmSet.access = collectionMapping.Access; + + bool batchsizeSpecified = collectionMapping.IsSpecified("BatchSize"); + hbmSet.batchsizeSpecified = batchsizeSpecified; + if (batchsizeSpecified) + hbmSet.batchsize = collectionMapping.BatchSize; + + if (collectionMapping.IsSpecified("Cascade")) + hbmSet.cascade = collectionMapping.Cascade; + + if (collectionMapping.IsSpecified("Check")) + hbmSet.check = collectionMapping.Check; + + if (collectionMapping.IsSpecified("CollectionType") && collectionMapping.CollectionType != TypeReference.Empty) + hbmSet.collectiontype = collectionMapping.CollectionType.ToString(); + + bool fetchSpecified = collectionMapping.IsSpecified("Fetch"); + hbmSet.fetchSpecified = fetchSpecified; + if (fetchSpecified) + hbmSet.fetch = LookupEnumValueIn(fetchDict, collectionMapping.Fetch); + + bool genericSpecified = collectionMapping.IsSpecified("Generic"); + hbmSet.genericSpecified = genericSpecified; + if (genericSpecified) + hbmSet.generic = collectionMapping.Generic; + + if (collectionMapping.IsSpecified("Inverse")) + hbmSet.inverse = collectionMapping.Inverse; + + bool lazySpecified = collectionMapping.IsSpecified("Lazy"); + hbmSet.lazySpecified = lazySpecified; + if (lazySpecified) + hbmSet.lazy = LookupEnumValueIn(FluentHbmLazyBiDict, collectionMapping.Lazy); + + if (collectionMapping.IsSpecified("Name")) + hbmSet.name = collectionMapping.Name; + + if (collectionMapping.IsSpecified("OptimisticLock")) + hbmSet.optimisticlock = collectionMapping.OptimisticLock; + + if (collectionMapping.IsSpecified("Persister")) + hbmSet.persister = collectionMapping.Persister.ToString(); + + if (collectionMapping.IsSpecified("Schema")) + hbmSet.schema = collectionMapping.Schema; + + if (collectionMapping.IsSpecified("TableName")) + hbmSet.table = collectionMapping.TableName; + + if (collectionMapping.IsSpecified("Where")) + hbmSet.where = collectionMapping.Where; + + if (collectionMapping.IsSpecified("Subselect")) + hbmSet.subselect = collectionMapping.Subselect.ToHbmSubselect(); + + if (collectionMapping.IsSpecified("Mutable")) + hbmSet.mutable = collectionMapping.Mutable; + + #endregion Base collection attributes + + #region Type-specific collection attributes + + if (collectionMapping.IsSpecified("OrderBy")) + hbmSet.orderby = collectionMapping.OrderBy; + + if (collectionMapping.IsSpecified("Sort")) + hbmSet.sort = collectionMapping.Sort; + + #endregion Type-specific collection attributes + } + + #region Base collection visitors + + public override void Visit(KeyMapping keyMapping) + { + hbmSet.key = ConvertFluentSubobjectToHibernateNative(keyMapping); + } + + public override void Visit(CacheMapping cacheMapping) + { + hbmSet.cache = ConvertFluentSubobjectToHibernateNative(cacheMapping); + } + + public override void Visit(ICollectionRelationshipMapping collectionRelationshipMapping) + { + // HbmSet.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + // (ManyToMany and OneToMany are implementations of ICollectionRelationshipMapping, and there is no mapping that lines up with ManyToAny) + hbmSet.Item = ConvertFluentSubobjectToHibernateNative(collectionRelationshipMapping); + } + + public override void Visit(CompositeElementMapping compositeElementMapping) + { + // HbmSet.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmSet.Item = ConvertFluentSubobjectToHibernateNative(compositeElementMapping); + } + + public override void Visit(ElementMapping elementMapping) + { + // HbmSet.Item is CompositeElement / Element / ManyToAny / ManyToMany / OneToMany + hbmSet.Item = ConvertFluentSubobjectToHibernateNative(elementMapping); + } + + public override void Visit(FilterMapping filterMapping) + { + AddToNullableArray(ref hbmSet.filter, ConvertFluentSubobjectToHibernateNative(filterMapping)); + } + + #endregion Base collection visitors + + #region Type-specific collection visitors + + // No type-specific visitors for this type + + #endregion Type-specific collection visitors + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmStoredProcedureConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmStoredProcedureConverter.cs new file mode 100644 index 000000000..a7d4a2d02 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmStoredProcedureConverter.cs @@ -0,0 +1,34 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmStoredProcedureConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary checkDict = new XmlLinkedEnumBiDictionary(); + + private HbmCustomSQL hbmCustomSQL; + + public HbmStoredProcedureConverter() : base(null) + { + } + + public override HbmCustomSQL Convert(StoredProcedureMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmCustomSQL; + } + + public override void ProcessStoredProcedure(StoredProcedureMapping storedProcedureMapping) + { + hbmCustomSQL = new HbmCustomSQL(); + + // Realistically, this is always considered specified, but this is arguably more correct if that ever changes + bool checkSpecified = storedProcedureMapping.IsSpecified("Check"); + hbmCustomSQL.checkSpecified = checkSpecified; + if (checkSpecified) + hbmCustomSQL.check = LookupEnumValueIn(checkDict, storedProcedureMapping.Check); + + hbmCustomSQL.Text = new string[] { storedProcedureMapping.Query }; + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmSubclassConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmSubclassConverter.cs new file mode 100644 index 000000000..43f2cfc08 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmSubclassConverter.cs @@ -0,0 +1,44 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmSubclassConverter : HbmConverterBase + { + private object hbmSubclass; + + public HbmSubclassConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override object Convert(SubclassMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmSubclass; + } + + public override void ProcessSubclass(SubclassMapping subclassMapping) + { + // Yes, this should really be a switch/case statement, but the way SubclassType is currently implemented + // makes that even uglier, for for now it gets to be a giant sequence of if blocks. + var subType = subclassMapping.SubclassType; + if (subType == SubclassType.Subclass) + { + hbmSubclass = ConvertFluentSubobjectToHibernateNative(subclassMapping); + } + else if (subType == SubclassType.JoinedSubclass) + { + hbmSubclass = ConvertFluentSubobjectToHibernateNative(subclassMapping); + } + else if (subType == SubclassType.UnionSubclass) + { + hbmSubclass = ConvertFluentSubobjectToHibernateNative(subclassMapping); + } + else + { + throw new NotSupportedException(string.Format("Subclass type {0} is not supported", subType)); + } + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmTuplizerConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmTuplizerConverter.cs new file mode 100644 index 000000000..f04a9405d --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmTuplizerConverter.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmTuplizerConverter : HbmConverterBase + { + public static readonly EnumBiDictionary FluentHbmEntityModeBiDict = new EnumBiDictionary( + new Dictionary() { + { HbmTuplizerEntitymode.Poco, TuplizerMode.Poco }, + { HbmTuplizerEntitymode.DynamicMap, TuplizerMode.DynamicMap }, + //{ , TuplizerMode.Xml }, + } + ); + + private HbmTuplizer hbmTuplizer; + + public HbmTuplizerConverter() : base(null) + { + } + + public override HbmTuplizer Convert(TuplizerMapping tuplizerMapping) + { + tuplizerMapping.AcceptVisitor(this); + return hbmTuplizer; + } + + public override void ProcessTuplizer(TuplizerMapping tuplizerMapping) + { + hbmTuplizer = new HbmTuplizer(); + + bool modeSpecified = tuplizerMapping.IsSpecified("Mode"); + hbmTuplizer.entitymodeSpecified = modeSpecified; + if (modeSpecified) + hbmTuplizer.entitymode = LookupEnumValueIn(FluentHbmEntityModeBiDict, tuplizerMapping.Mode); + + if (tuplizerMapping.IsSpecified("Type")) + hbmTuplizer.@class = tuplizerMapping.Type.ToString(); + + // The XML variant of this logic supports an EntityName attribute, but that does not appear in either HbmTuplizer or + // the XSD, so it appears to be an error. Since we have nowhere to write it, just silently ignore it, even if it is + // set. + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/HbmUnionSubclassConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmUnionSubclassConverter.cs new file mode 100644 index 000000000..671190fc0 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmUnionSubclassConverter.cs @@ -0,0 +1,155 @@ +using System; +using FluentNHibernate.MappingModel.ClassBased; +using FluentNHibernate.MappingModel.Collections; +using FluentNHibernate.Utils; +using NHibernate.Cfg.MappingSchema; +using IComponentMapping = FluentNHibernate.MappingModel.ClassBased.IComponentMapping; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmUnionSubclassConverter : HbmConverterBase + { + private HbmUnionSubclass hbmUnionSubclass; + + public HbmUnionSubclassConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmUnionSubclass Convert(SubclassMapping mapping) + { + mapping.AcceptVisitor(this); + return hbmUnionSubclass; + } + + public override void ProcessSubclass(SubclassMapping subclassMapping) + { + hbmUnionSubclass = new HbmUnionSubclass(); + + if (subclassMapping.IsSpecified("Name")) + hbmUnionSubclass.name = subclassMapping.Name; + + if (subclassMapping.IsSpecified("Proxy")) + hbmUnionSubclass.proxy = subclassMapping.Proxy; + + bool lazySpecified = subclassMapping.IsSpecified("Lazy"); + hbmUnionSubclass.lazySpecified = lazySpecified; + if (lazySpecified) + hbmUnionSubclass.lazy = subclassMapping.Lazy; + + if (subclassMapping.IsSpecified("DynamicUpdate")) + hbmUnionSubclass.dynamicupdate = subclassMapping.DynamicUpdate; + + if (subclassMapping.IsSpecified("DynamicInsert")) + hbmUnionSubclass.dynamicinsert = subclassMapping.DynamicInsert; + + if (subclassMapping.IsSpecified("SelectBeforeUpdate")) + hbmUnionSubclass.selectbeforeupdate = subclassMapping.SelectBeforeUpdate; + + bool abstractSpecified = subclassMapping.IsSpecified("Abstract"); + hbmUnionSubclass.abstractSpecified = abstractSpecified; + if (abstractSpecified) + hbmUnionSubclass.@abstract = subclassMapping.Abstract; + + if (subclassMapping.IsSpecified("EntityName")) + hbmUnionSubclass.entityname = subclassMapping.EntityName; + + if (subclassMapping.IsSpecified("BatchSize")) + hbmUnionSubclass.batchsize = subclassMapping.BatchSize.ToString(); + + if (subclassMapping.IsSpecified("TableName")) + hbmUnionSubclass.table = subclassMapping.TableName; + + if (subclassMapping.IsSpecified("Schema")) + hbmUnionSubclass.schema = subclassMapping.Schema; + + if (subclassMapping.IsSpecified("Check")) + hbmUnionSubclass.check = subclassMapping.Check; + + if (subclassMapping.IsSpecified("Subselect")) + hbmUnionSubclass.subselect = subclassMapping.Subselect.ToHbmSubselect(); + + if (subclassMapping.IsSpecified("Persister")) + hbmUnionSubclass.persister = subclassMapping.Persister.ToString(); + } + + #region Methods paralleling XmlSubclassWriter + + public override void Visit(SubclassMapping subclassMapping) + { + var subType = subclassMapping.SubclassType; + if (subType == SubclassType.UnionSubclass) + { + AddToNullableArray(ref hbmUnionSubclass.unionsubclass1, ConvertFluentSubobjectToHibernateNative(subclassMapping)); + } + else + { + throw new NotSupportedException(string.Format("Cannot mix subclass types (subclass type {0} not supported within subclass type {1})", subType, SubclassType.Subclass)); + } + } + + public override void Visit(IComponentMapping componentMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (ComponentMapping, ExternalComponentMapping, and ReferenceComponentMapping are implementations of IComponentMapping, while + // DynamicComponentMapping is a refinement of ComponentMapping) + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(componentMapping)); + } + + #endregion Methods paralleling XmlSubclassWriter + + #region Methods paralleling XmlClassWriterBase + + public override void Visit(PropertyMapping propertyMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(propertyMapping)); + } + + public override void Visit(OneToOneMapping oneToOneMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(oneToOneMapping)); + } + + public override void Visit(ManyToOneMapping manyToOneMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(manyToOneMapping)); + } + + public override void Visit(AnyMapping anyMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(anyMapping)); + } + + public override void Visit(CollectionMapping collectionMapping) + { + // HbmUnionSubclass.Items is Any / Array / Bag / Component / DynamicComponent / Idbag / List / ManyToOne / Map / OneToOne / PrimitiveArray / Properties / Property / Set + // (array, bag, list, map, and set are refinements of CollectionMapping, while idbag and primitivearray do not yet appear to be implemented) + AddToNullableArray(ref hbmUnionSubclass.Items, ConvertFluentSubobjectToHibernateNative(collectionMapping)); + } + + public override void Visit(StoredProcedureMapping storedProcedureMapping) + { + var spType = storedProcedureMapping.SPType; + var sprocSql = ConvertFluentSubobjectToHibernateNative(storedProcedureMapping); + switch (spType) + { + case "sql-insert": + hbmUnionSubclass.sqlinsert = sprocSql; + break; + case "sql-update": + hbmUnionSubclass.sqlupdate = sprocSql; + break; + case "sql-delete": + hbmUnionSubclass.sqldelete = sprocSql; + break; + default: + throw new NotSupportedException(string.Format("Stored procedure type {0} is not supported", spType)); + } + } + + #endregion Methods paralleling XmlClassWriterBase + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/HbmVersionConverter.cs b/src/FluentNHibernate/MappingModel/Output/HbmVersionConverter.cs new file mode 100644 index 000000000..072c4031f --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/HbmVersionConverter.cs @@ -0,0 +1,46 @@ +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class HbmVersionConverter : HbmConverterBase + { + private static readonly XmlLinkedEnumBiDictionary genDict = new XmlLinkedEnumBiDictionary(); + + private HbmVersion hbmVersion; + + public HbmVersionConverter(IHbmConverterServiceLocator serviceLocator) : base(serviceLocator) + { + } + + public override HbmVersion Convert(VersionMapping versionMapping) + { + versionMapping.AcceptVisitor(this); + return hbmVersion; + } + + public override void ProcessVersion(VersionMapping versionMapping) + { + hbmVersion = new HbmVersion(); + + if (versionMapping.IsSpecified("Access")) + hbmVersion.access = versionMapping.Access; + + if (versionMapping.IsSpecified("Generated")) + hbmVersion.generated = LookupEnumValueIn(genDict, versionMapping.Generated); + + if (versionMapping.IsSpecified("Name")) + hbmVersion.name = versionMapping.Name; + + if (versionMapping.IsSpecified("Type")) + hbmVersion.type = versionMapping.Type.ToString(); + + if (versionMapping.IsSpecified("UnsavedValue")) + hbmVersion.unsavedvalue = versionMapping.UnsavedValue; + } + + public override void Visit(ColumnMapping columnMapping) + { + AddToNullableArray(ref hbmVersion.column, ConvertFluentSubobjectToHibernateNative(columnMapping)); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/IHbmConverter.cs b/src/FluentNHibernate/MappingModel/Output/IHbmConverter.cs new file mode 100644 index 000000000..b2bc3d01b --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/IHbmConverter.cs @@ -0,0 +1,7 @@ +namespace FluentNHibernate.MappingModel.Output +{ + public interface IHbmConverter + { + H Convert(F fluentMapping); + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/IHbmConverterServiceLocator.cs b/src/FluentNHibernate/MappingModel/Output/IHbmConverterServiceLocator.cs new file mode 100644 index 000000000..80e4b7211 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/IHbmConverterServiceLocator.cs @@ -0,0 +1,7 @@ +namespace FluentNHibernate.MappingModel.Output +{ + public interface IHbmConverterServiceLocator + { + IHbmConverter GetConverter(); + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/MappingApplicationStrategyBase.cs b/src/FluentNHibernate/MappingModel/Output/MappingApplicationStrategyBase.cs new file mode 100644 index 000000000..2989c22ce --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/MappingApplicationStrategyBase.cs @@ -0,0 +1,53 @@ +using NHibernate.Cfg; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace FluentNHibernate.MappingModel.Output +{ + /// + /// A two-stage mapping application strategy which first transforms a into an intermediate + /// form, and then applies the intermediate form to a . The stages are separated in order to + /// address thread safety considerations; see the documentation for and + /// for details. + /// + /// Intermediate type used by this strategy + public abstract class MappingApplicationStrategyBase : IMappingApplicationStrategy + { + protected MappingApplicationStrategyBase() + { + } + + /// + /// Translate a to the intermediate form. Implementations of this method must be + /// thread-safe and should expect that they may run with a high degree of parallelism. + /// + /// a fluent Hibernate mapping + /// the intermediate translation of the input mapping + protected abstract I ToIntermediateForm(HibernateMapping mapping); + + /// + /// Apply a translated mapping to a . Implementations of this method are not required + /// to be thread-safe, and may safely assume that calls to this method will be invoked serially. + /// + /// a translated Hibernate mapping + /// the target configuration + protected abstract void ApplyIntermediateFormToConfiguration(I intermediateForm, Configuration cfg); + + public void ApplyMappingsToConfiguration(IEnumerable mappings, Configuration cfg, int degreeOfParallelism) + { + foreach (var intermediate in mappings.Where(m => !m.Classes.Any()).AsParallel().AsOrdered().WithDegreeOfParallelism(degreeOfParallelism).Select(m => ToIntermediateForm(m))) + { + ApplyIntermediateFormToConfiguration(intermediate, cfg); + } + + foreach (var mappingAndIntermediate in mappings.Where(m => m.Classes.Any()).AsParallel().AsOrdered().WithDegreeOfParallelism(degreeOfParallelism).Select(m => Tuple.Create(m, ToIntermediateForm(m)))) + { + var mapping = mappingAndIntermediate.Item1; + var intermediate = mappingAndIntermediate.Item2; + if (cfg.GetClassMapping(mapping.Classes.First().Type) == null) + ApplyIntermediateFormToConfiguration(intermediate, cfg); + } + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/MappingHbmConverter.cs b/src/FluentNHibernate/MappingModel/Output/MappingHbmConverter.cs new file mode 100644 index 000000000..9214bdb85 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/MappingHbmConverter.cs @@ -0,0 +1,20 @@ +using System.Xml; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + public class MappingHbmConverter + { + public HbmMapping Convert(HibernateMapping mapping) + { + return BuildHbm(mapping); + } + + private static HbmMapping BuildHbm(HibernateMapping rootMapping) + { + var hbmConverter = HbmConverterFactory.CreateHibernateMappingConverter(); + + return hbmConverter.Convert(rootMapping); + } + } +} \ No newline at end of file diff --git a/src/FluentNHibernate/MappingModel/Output/ValidatingHbmMappingApplicationStrategy.cs b/src/FluentNHibernate/MappingModel/Output/ValidatingHbmMappingApplicationStrategy.cs new file mode 100644 index 000000000..7c7d47761 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/ValidatingHbmMappingApplicationStrategy.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using FluentNHibernate.MappingModel.Collections; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; + +namespace FluentNHibernate.MappingModel.Output +{ + /// + /// A mapping application strategy which utilizes both and + /// for translation, checking that the results align before using the HBM variant. + /// + public class ValidatingHbmMappingApplicationStrategy : MappingApplicationStrategyBase> + { + public ValidatingHbmMappingApplicationStrategy() + { + } + + protected override Tuple ToIntermediateForm(HibernateMapping mapping) + { + var document = new MappingXmlSerializer().Serialize(mapping); + var hbm = new MappingHbmConverter().Convert(mapping); + + return new Tuple(document, hbm); + } + + protected override void ApplyIntermediateFormToConfiguration(Tuple intermediateForm, Configuration cfg) + { + var document = intermediateForm.Item1; + // Note that cfg.LoadMappingDocument isn't necessarily thread safe, but we can't guarantee thread safety for this + // method anyway, so it shouldn't be an issue. + var loadedHbmMapping = cfg.LoadMappingDocument(new XmlTextReader(document.InnerXml, XmlNodeType.Document, null), "(SerializedXmlDocument)").Document; + var directHbmMapping = intermediateForm.Item2; + + string loadedHbmJson = ToJson(loadedHbmMapping); + string directHbmJson = ToJson(directHbmMapping); + if (loadedHbmJson != directHbmJson) + throw new Exception("Loaded and direct HBM mappings did not match\nLoaded:\n" + loadedHbmJson + "\n!=\nDirect:\n" + directHbmJson); + + cfg.AddDeserializedMapping(directHbmMapping, "(XmlDocument)"); + } + + private static readonly IReadOnlyList KnownTypes = new List() { + typeof(NHibernate.Type.Int32Type), + typeof(Dictionary), + typeof(HbmAny), + typeof(HbmArray), + typeof(HbmBag), + typeof(HbmCache), + typeof(HbmClass), + typeof(HbmColumn), + typeof(HbmComponent), + typeof(HbmCompositeElement), + typeof(HbmCompositeId), + typeof(HbmCustomSQL), + typeof(HbmDiscriminator), + typeof(HbmDynamicComponent), + typeof(HbmElement), + typeof(HbmFilter), + typeof(HbmFilterDef), + typeof(HbmGenerator), + typeof(HbmId), + typeof(HbmImport), + typeof(HbmIndex), + typeof(HbmIndexManyToMany), + typeof(HbmJoin), + typeof(HbmJoinedSubclass), + typeof(HbmKey), + typeof(HbmKeyManyToOne), + typeof(HbmKeyProperty), + typeof(HbmList), + typeof(HbmListIndex), + typeof(HbmManyToMany), + typeof(HbmManyToOne), + typeof(HbmMap), + typeof(HbmMetaValue), + typeof(HbmNaturalId), + typeof(HbmNestedCompositeElement), + typeof(HbmOneToMany), + typeof(HbmOneToOne), + typeof(HbmParent), + typeof(HbmProperty), + typeof(HbmSet), + typeof(HbmSubclass), + typeof(HbmTuplizer), + typeof(HbmUnionSubclass), + typeof(HbmVersion), + }; + + private string ToJson(object mapping) + { + DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(mapping.GetType(), KnownTypes); + MemoryStream memStream = new MemoryStream(); + jsonSerializer.WriteObject(memStream, mapping); + return Encoding.Default.GetString(memStream.ToArray()); + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/XmlLinkedEnumBiDictionary.cs b/src/FluentNHibernate/MappingModel/Output/XmlLinkedEnumBiDictionary.cs new file mode 100644 index 000000000..7eab4c1f4 --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/XmlLinkedEnumBiDictionary.cs @@ -0,0 +1,14 @@ +using System; +using System.Xml.Serialization; +using FluentNHibernate.Utils; + +namespace FluentNHibernate.MappingModel.Output +{ + public class XmlLinkedEnumBiDictionary : EnumBiDictionary + where E : Enum + { + public XmlLinkedEnumBiDictionary() : base(e => e.GetCustomAttribute().Name) + { + } + } +} diff --git a/src/FluentNHibernate/MappingModel/Output/XmlMappingApplicationStrategy.cs b/src/FluentNHibernate/MappingModel/Output/XmlMappingApplicationStrategy.cs new file mode 100644 index 000000000..35a90141e --- /dev/null +++ b/src/FluentNHibernate/MappingModel/Output/XmlMappingApplicationStrategy.cs @@ -0,0 +1,25 @@ +using System.Xml; +using NHibernate.Cfg; + +namespace FluentNHibernate.MappingModel.Output +{ + /// + /// A mapping application strategy which utilizes for translation. + /// + public class XmlMappingApplicationStrategy : MappingApplicationStrategyBase + { + public XmlMappingApplicationStrategy() + { + } + + protected override XmlDocument ToIntermediateForm(HibernateMapping mapping) + { + return new MappingXmlSerializer().Serialize(mapping); + } + + protected override void ApplyIntermediateFormToConfiguration(XmlDocument intermediateForm, Configuration cfg) + { + cfg.AddDocument(intermediateForm); + } + } +} diff --git a/src/FluentNHibernate/PersistenceModel.cs b/src/FluentNHibernate/PersistenceModel.cs index 2b8807a8b..6d54b7cc2 100644 --- a/src/FluentNHibernate/PersistenceModel.cs +++ b/src/FluentNHibernate/PersistenceModel.cs @@ -35,6 +35,8 @@ public class PersistenceModel public bool MergeMappings { get; set; } private IEnumerable compiledMappings; private ValidationVisitor validationVisitor; + public int DegreeOfParallelism { get; set; } = 1; + public IMappingApplicationStrategy MappingApplicationStrategy { get; set; } = new XmlMappingApplicationStrategy(); public PairBiDirectionalManyToManySidesDelegate BiDirectionalManyToManyPairer { get; set; } IDiagnosticMessageDispatcher diagnosticDispatcher = new DefaultDiagnosticMessageDispatcher(); @@ -77,12 +79,15 @@ public void AddMappingsFromAssembly(Assembly assembly) public void AddMappingsFromSource(ITypeSource source) { - source.GetTypes() + foreach (object o in source.GetTypes() .Where(x => IsMappingOf(x) || IsMappingOf(x) || IsMappingOf(x) || IsMappingOf(x)) - .Each(Add); + .AsParallel().AsOrdered().WithDegreeOfParallelism(DegreeOfParallelism).Select(t => t.InstantiateUsingParameterlessConstructor()).ToList()) + { + AddObject(o); + } log.LoadedFluentMappingsFromSource(source); } @@ -129,7 +134,11 @@ public void Add(IExternalComponentMappingProvider provider) public void Add(Type type) { var mapping = type.InstantiateUsingParameterlessConstructor(); - + AddObject(mapping); + } + public void AddObject(object mapping) + { + Type type = mapping.GetType(); if (mapping is IMappingProvider) { log.FluentMappingDiscovered(type); @@ -276,21 +285,7 @@ public virtual void Configure(Configuration cfg) { EnsureMappingsBuilt(); - foreach (var mapping in compiledMappings.Where(m => !m.Classes.Any())) - { - var serializer = new MappingXmlSerializer(); - XmlDocument document = serializer.Serialize(mapping); - cfg.AddDocument(document); - } - - foreach (var mapping in compiledMappings.Where(m => m.Classes.Any())) - { - var serializer = new MappingXmlSerializer(); - XmlDocument document = serializer.Serialize(mapping); - - if (cfg.GetClassMapping(mapping.Classes.First().Type) == null) - cfg.AddDocument(document); - } + MappingApplicationStrategy.ApplyMappingsToConfiguration(compiledMappings, cfg, DegreeOfParallelism); } public bool ContainsMapping(Type type) @@ -364,4 +359,9 @@ public IEnumerable GetIgnoredProperties() return new Member[0]; } } + + public interface IMappingApplicationStrategy + { + void ApplyMappingsToConfiguration(IEnumerable mappings, Configuration cfg, int degreeOfParallelism); + } } \ No newline at end of file diff --git a/src/FluentNHibernate/Utils/Extensions.cs b/src/FluentNHibernate/Utils/Extensions.cs index b21a1dcde..7e28eda46 100644 --- a/src/FluentNHibernate/Utils/Extensions.cs +++ b/src/FluentNHibernate/Utils/Extensions.cs @@ -91,5 +91,13 @@ public static bool IsAutoMappingOverrideType(this Type type) { return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IAutoMappingOverride<>) && type.GetGenericArguments().Length > 0; } + + public static T GetCustomAttribute(this Enum enumValue) + { + var enumType = enumValue.GetType(); + var memberInfos = enumType.GetMember(Enum.GetName(enumType, enumValue)); + var attrs = memberInfos[0].GetCustomAttributes(typeof(T), false); + return (T)attrs.FirstOrDefault(); + } } } \ No newline at end of file diff --git a/src/FluentNHibernate/Utils/HbmExtensions.cs b/src/FluentNHibernate/Utils/HbmExtensions.cs new file mode 100644 index 000000000..460b13b85 --- /dev/null +++ b/src/FluentNHibernate/Utils/HbmExtensions.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Linq; +using FluentNHibernate.MappingModel; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Type; + +namespace FluentNHibernate.Utils +{ + public static class HbmExtensions + { + public static HbmType ToHbmType(this TypeReference typeReference) + { + return new HbmType() + { + name = typeReference.Name, + }; + } + + public static HbmParam ToHbmParam(this KeyValuePair parameterPair) + { + return new HbmParam() + { + name = parameterPair.Key, + Text = new string[] { parameterPair.Value } + }; + } + + public static HbmFilterParam ToHbmFilterParam(this KeyValuePair parameterPair) + { + return new HbmFilterParam() + { + name = parameterPair.Key, + type = parameterPair.Value.Name + }; + } + + public static HbmSubselect ToHbmSubselect(this string content) + { + return new string[] { content }.ToHbmSubselect(); + } + + public static HbmSubselect ToHbmSubselect(this string[] content) + { + return new HbmSubselect() + { + Text = content.ToArray() // Simple way to get a typesafe defensive copy of the input array + }; + } + } +} \ No newline at end of file