Skip to content

Commit

Permalink
Added fix for duplicate columns in keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jagregory committed May 23, 2010
1 parent b6fd4bc commit 7674a4d
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 31 deletions.
3 changes: 3 additions & 0 deletions src/FluentNHibernate.Specs/Automapping/OverrideSpecs.cs
Expand Up @@ -43,7 +43,10 @@ public class when_using_an_automapping_override_to_specify_a_discriminator
mapping.Discriminator.ShouldNotBeNull();

It should_map_subclasses_as_subclass_instead_of_joined_subclass = () =>
{
mapping.Subclasses.Count().ShouldEqual(1);
mapping.Subclasses.ShouldEachConformTo(x => x.SubclassType == SubclassType.Subclass);
};

static AutoPersistenceModel model;
static ClassMapping mapping;
Expand Down
5 changes: 1 addition & 4 deletions src/FluentNHibernate.Specs/FluentInterface/ProviderSpec.cs
Expand Up @@ -19,13 +19,10 @@ public static ClassMapping map_as_class<T>(Action<ClassMap<T>> setup)
public static SubclassMapping map_as_subclass<T>(Action<SubclassMap<T>> setup)
{
var provider = new SubclassMap<T>();
var mapping = new SubclassMapping(SubclassType.Subclass);

setup(provider);

((IIndeterminateSubclassMappingProvider)provider).GetSubclassMapping(mapping);

return mapping;
return ((IIndeterminateSubclassMappingProvider)provider).GetSubclassMapping(SubclassType.Subclass);
}
}
}
82 changes: 81 additions & 1 deletion src/FluentNHibernate.Specs/PersistenceModel/SubclassSpecs.cs
@@ -1,7 +1,13 @@
using System.Linq;
using System.Collections.Generic;
using System.Linq;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using FluentNHibernate.MappingModel;
using FluentNHibernate.MappingModel.ClassBased;
using FluentNHibernate.Specs.PersistenceModel.Fixtures;
using Machine.Specifications;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace FluentNHibernate.Specs.PersistenceModel
{
Expand All @@ -23,4 +29,78 @@ public class when_subclass_map_is_combined_with_a_class_map_flagged_as_union
static FluentNHibernate.PersistenceModel model;
static ClassMapping mapping;
}

public class when_subclass_map_has_a_has_many_to_another_entity
{
Establish context = () =>
{
model = new FluentNHibernate.PersistenceModel();
model.Add(new ProductMap());
model.Add(new SpecialProductMap());
model.Add(new OptionMap());
cfg = new Configuration();
SQLiteConfiguration.Standard.InMemory()
.ConfigureProperties(cfg);
model.Configure(cfg);
new SchemaExport(cfg).Create(true, false);
};

Because of = () =>
mappings = model.BuildMappings()
.SelectMany(x => x.Classes);

It should_only_use_one_column_in_the_target_entity_s_key = () =>
mappings.Single(x => x.Type == typeof(Product))
.Subclasses.Single()
.Collections.Single()
.Key.Columns.Select(x => x.Name)
.ShouldContainOnly("SpecialProduct_id");

static FluentNHibernate.PersistenceModel model;
static IEnumerable<ClassMapping> mappings;
static Configuration cfg;

class Product
{
public int ProductId { get; set; }
}

class SpecialProduct : Product
{
public ICollection<Option> Options { get; set;}
}

class Option
{
public int OptionId { get; set; }
public SpecialProduct Back { get; set; }
}

class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.ProductId);
}
}

class SpecialProductMap : SubclassMap<SpecialProduct>
{
public SpecialProductMap()
{
Extends<Product>();
HasMany(x => x.Options).Cascade.AllDeleteOrphan();
}
}

class OptionMap : ClassMap<Option>
{
public OptionMap()
{
Id(x => x.OptionId);
}
}
}
}
Expand Up @@ -37,7 +37,7 @@ public abstract class BaseModelFixture

protected ModelTester<SubclassMap<T>, SubclassMapping> SubclassMapForSubclass<T>()
{
return new ModelTester<SubclassMap<T>, SubclassMapping>(() => new SubclassMap<T>(), x => ((IIndeterminateSubclassMappingProvider)x).GetSubclassMapping(new SubclassMapping(SubclassType.Subclass)));
return new ModelTester<SubclassMap<T>, SubclassMapping>(() => new SubclassMap<T>(), x => ((IIndeterminateSubclassMappingProvider)x).GetSubclassMapping(SubclassType.Subclass));
}

protected ModelTester<JoinedSubClassPart<T>, SubclassMapping> JoinedSubclass<T>()
Expand All @@ -47,7 +47,7 @@ public abstract class BaseModelFixture

protected ModelTester<SubclassMap<T>, SubclassMapping> SubclassMapForJoinedSubclass<T>()
{
return new ModelTester<SubclassMap<T>, SubclassMapping>(() => new SubclassMap<T>(), x => ((IIndeterminateSubclassMappingProvider)x).GetSubclassMapping(new SubclassMapping(SubclassType.JoinedSubclass)));
return new ModelTester<SubclassMap<T>, SubclassMapping>(() => new SubclassMap<T>(), x => ((IIndeterminateSubclassMappingProvider)x).GetSubclassMapping(SubclassType.JoinedSubclass));
}

protected ModelTester<ComponentPart<T>, ComponentMapping> Component<T>()
Expand Down
2 changes: 1 addition & 1 deletion src/FluentNHibernate/FluentNHibernate.csproj
Expand Up @@ -410,6 +410,7 @@
<Compile Include="Mapping\Providers\IExternalComponentMappingProvider.cs" />
<Compile Include="Mapping\Providers\INaturalIdMappingProvider.cs" />
<Compile Include="Mapping\Providers\INestedCompositeElementMappingProvider.cs" />
<Compile Include="Mapping\Providers\IPropertyMappingProvider.cs" />
<Compile Include="Mapping\Providers\IReferenceComponentMappingProvider.cs" />
<Compile Include="Mapping\TuplizerPart.cs" />
<Compile Include="Utils\StringLikeness.cs" />
Expand Down Expand Up @@ -468,7 +469,6 @@
<Compile Include="Mapping\Providers\IJoinMappingProvider.cs" />
<Compile Include="Mapping\Providers\IManyToOneMappingProvider.cs" />
<Compile Include="Mapping\Providers\IOneToOneMappingProvider.cs" />
<Compile Include="Mapping\Providers\IPropertyMappingProvider.cs" />
<Compile Include="Mapping\Providers\IIndeterminateSubclassMappingProvider.cs" />
<Compile Include="Mapping\Providers\IVersionMappingProvider.cs" />
<Compile Include="Mapping\SubclassMap.cs" />
Expand Down
Expand Up @@ -5,7 +5,7 @@ namespace FluentNHibernate.Mapping.Providers
{
public interface IIndeterminateSubclassMappingProvider
{
SubclassMapping GetSubclassMapping(SubclassMapping mapping);
SubclassMapping GetSubclassMapping(SubclassType type);
Type EntityType { get; }
Type Extends { get; }
}
Expand Down
10 changes: 6 additions & 4 deletions src/FluentNHibernate/Mapping/SubclassMap.cs
Expand Up @@ -4,6 +4,7 @@
using FluentNHibernate.Mapping.Providers;
using FluentNHibernate.MappingModel;
using FluentNHibernate.MappingModel.ClassBased;
using FluentNHibernate.Utils;

namespace FluentNHibernate.Mapping
{
Expand Down Expand Up @@ -269,8 +270,10 @@ public void Extends(Type type)
attributes.Set(x => x.Extends, type);
}

SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(SubclassMapping mapping)
SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(SubclassType type)
{
var mapping = new SubclassMapping(type);

GenerateNestedSubclasses(mapping);

attributes.SetDefault(x => x.Type, typeof(T));
Expand Down Expand Up @@ -308,7 +311,7 @@ SubclassMapping IIndeterminateSubclassMappingProvider.GetSubclassMapping(Subclas
foreach (var any in anys)
mapping.AddAny(any.GetAnyMapping());

return mapping;
return mapping.DeepClone();
}

Type IIndeterminateSubclassMappingProvider.Extends
Expand All @@ -320,8 +323,7 @@ void GenerateNestedSubclasses(SubclassMapping mapping)
{
foreach (var subclassType in indetermineateSubclasses.Keys)
{
var emptySubclassMapping = new SubclassMapping(mapping.SubclassType);
var subclassMapping = indetermineateSubclasses[subclassType].GetSubclassMapping(emptySubclassMapping);
var subclassMapping = indetermineateSubclasses[subclassType].GetSubclassMapping(mapping.SubclassType);

mapping.AddSubclass(subclassMapping);
}
Expand Down
17 changes: 17 additions & 0 deletions src/FluentNHibernate/MappingModel/ClassBased/ComponentType.cs
Expand Up @@ -19,5 +19,22 @@ public string GetElementName()
{
return elementName;
}

public override bool Equals(object obj)
{
if (obj is ComponentType)
return Equals(obj as ComponentType);
return false;
}

public bool Equals(ComponentType other)
{
return Equals(other.elementName, elementName);
}

public override int GetHashCode()
{
return (elementName != null ? elementName.GetHashCode() : 0);
}
}
}
17 changes: 13 additions & 4 deletions src/FluentNHibernate/MappingModel/ClassBased/SubclassType.cs
@@ -1,5 +1,8 @@
using System;

namespace FluentNHibernate.MappingModel.ClassBased
{
[Serializable]
public class SubclassType
{
public static readonly SubclassType Subclass = new SubclassType("subclass");
Expand All @@ -20,15 +23,11 @@ public string GetElementName()

public bool Equals(SubclassType other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other.elementName, elementName);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof(SubclassType)) return false;
return Equals((SubclassType)obj);
}
Expand All @@ -42,5 +41,15 @@ public override string ToString()
{
return string.Format("ElementName: {0}", elementName);
}

public static bool operator ==(SubclassType left, SubclassType right)
{
return Equals(left, right);
}

public static bool operator !=(SubclassType left, SubclassType right)
{
return !(left == right);
}
}
}
4 changes: 0 additions & 4 deletions src/FluentNHibernate/MappingModel/ColumnMapping.cs
Expand Up @@ -118,15 +118,11 @@ public ColumnMapping Clone()

public bool Equals(ColumnMapping other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other.attributes, attributes) && Equals(other.Member, Member);
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != typeof(ColumnMapping)) return false;
return Equals((ColumnMapping)obj);
}
Expand Down
4 changes: 2 additions & 2 deletions src/FluentNHibernate/MappingModel/DefaultableList.cs
Expand Up @@ -62,7 +62,7 @@ public void ClearAll()

public bool Contains(T item)
{
return userDefined.Contains(item);
return userDefined.Contains(item) || ContainsDefault(item);
}

public bool ContainsDefault(T item)
Expand Down Expand Up @@ -117,7 +117,7 @@ public int CountDefaults

public int CountAll
{
get { return Count + CountDefaults; }
get { return userDefined.Count + CountDefaults; }
}

public bool IsReadOnly
Expand Down
8 changes: 6 additions & 2 deletions src/FluentNHibernate/MappingModel/KeyMapping.cs
@@ -1,7 +1,5 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
using FluentNHibernate.Utils;
using FluentNHibernate.Visitors;

namespace FluentNHibernate.MappingModel
Expand Down Expand Up @@ -73,11 +71,17 @@ public IDefaultableEnumerable<ColumnMapping> Columns

public void AddColumn(ColumnMapping mapping)
{
if (columns.Contains(mapping))
return;

columns.Add(mapping);
}

public void AddDefaultColumn(ColumnMapping mapping)
{
if (columns.Contains(mapping))
return;

columns.AddDefault(mapping);
}

Expand Down
12 changes: 6 additions & 6 deletions src/FluentNHibernate/Visitors/SeparateSubclassVisitor.cs
Expand Up @@ -21,7 +21,7 @@ public override void ProcessClass(ClassMapping mapping)
var subclasses = FindClosestSubclasses(mapping.Type);

foreach (var provider in subclasses)
mapping.AddSubclass(provider.GetSubclassMapping(CreateSubclass(mapping)));
mapping.AddSubclass(provider.GetSubclassMapping(GetSubclassType(mapping)));

base.ProcessClass(mapping);
}
Expand All @@ -31,7 +31,7 @@ public override void ProcessSubclass(SubclassMapping mapping)
var subclasses = FindClosestSubclasses(mapping.Type);

foreach (var provider in subclasses)
mapping.AddSubclass(provider.GetSubclassMapping(new SubclassMapping(mapping.SubclassType)));
mapping.AddSubclass(provider.GetSubclassMapping(mapping.SubclassType));

base.ProcessSubclass(mapping);
}
Expand All @@ -52,17 +52,17 @@ private IEnumerable<IIndeterminateSubclassMappingProvider> FindClosestSubclasses
return subclasses[lowestDistance].Concat(extendsSubclasses);
}

private SubclassMapping CreateSubclass(ClassMapping mapping)
private SubclassType GetSubclassType(ClassMapping mapping)
{
if (mapping.IsUnionSubclass)
{
return new SubclassMapping(SubclassType.UnionSubclass);
return SubclassType.UnionSubclass;
}

if (mapping.Discriminator == null)
return new SubclassMapping(SubclassType.JoinedSubclass);
return SubclassType.JoinedSubclass;

return new SubclassMapping(SubclassType.Subclass);
return SubclassType.Subclass;
}

private bool IsMapped(Type type, IEnumerable<IIndeterminateSubclassMappingProvider> providers)
Expand Down

0 comments on commit 7674a4d

Please sign in to comment.