Unidirectional one-to-many NHibernate mapping failing when using FluentNHibernate PersistenceSpecification - nhibernate

I have a domain model where a Order has many LineItems. When I create a new Order (with new LineItems) and use PersistenceSpecification to test the mapping, NHibernate throws a PropertyValueException:
var order = new Order() { LineItems = new List<LineItem>() };
order.LineItems.Add(new LineItem());
new PersistenceSpecification<Order>(session)
.CheckList(o => o.LineItems, order.LineItems) // PropertyValueException
.VerifyTheMappings();
NHibernate.PropertyValueException: not-null property references a null or transient value LineItem._Order.LineItemsBackref
Domain model
public class Order {
public virtual Guid Id { get; set; }
public virtual ICollection<LineItem> LineItems { get; set; }
[...]
}
public class LineItem {
public virtual Guid Id { get; set; }
[...]
}
A LineItem on its own is not interesting, and they will never appear without a Order, so the relationship is unidirectional.
Fluent Mappings/Schema
// OrderMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();
HasMany(x => x.LineItems)
.Not.Inverse()
.Not.KeyNullable()
.Not.KeyUpdate()
.Cascade.AllDeleteOrphan();
// LineItemMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();
// Schema
CREATE TABLE Orders ( Id uniqueidentifier NOT NULL, /* ... */ )
CREATE TABLE LineItems ( Id uniqueidentifier NOT NULL,
OrderId uniqueidentifier NOT NULL, /* ... */ )
The foreign key column in the LineItems table is not nullable, so based on the information in this question I specified Not.KeyNullable() and Not.Inverse() to prevent NHibernate from attempting to insert a LineItem with a NULL Id.
I'm using NHibernate 3.3.2.400 and FluentNHibernate 1.3.0.733 (the current latest versions from NuGet).

This occurs because the CheckList() method tries to save each item in the list as soon as you call it. At this point, the parent entity hasn't been saved yet -- That doesn't happen until you call VerifyTheMappings().
Since the relationship is unidirectional, a child entity (LineItem) can't be persisted unless it is part of a parent (Order), and the exception is thrown. (GitHub issue)
I don't have a solution for this yet other than "don't bother testing the list mapping".

Related

Failed executing DbCommand ON DELETE NO ACTION

I am working on an ASP.NET Core project using code first I want to alter database design.
I have a case were I need to add two foreign keys to the same table, even I used DeleteBehavior.Restrict, still the error occurred when I update database.
Models:
public class Languages
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Projects> PFromLanguages { get; set; }
public virtual ICollection<Projects> PToLanguages { get; set; }
}
public class Projects
{
public int Id { get; set; }
public int FromLanguageId { get; set; }
public int ToLanguageId { get; set; }
public virtual Languages FromLanguage { get; set; }
public virtual Languages ToLanguage { get; set; }
}
Db Context:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Projects>()
.HasOne(p => p.FromLanguage)
.WithMany(b => b.PFromLanguages)
.HasForeignKey(b => b.FromLanguageId)
.OnDelete(DeleteBehavior.Restrict);
builder.Entity<Projects>()
.HasOne(p => p.ToLanguage)
.WithMany(b => b.PToLanguages)
.HasForeignKey(b => b.ToLanguageId)
.OnDelete(DeleteBehavior.Restrict);
}
Migration:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddForeignKey(
name: "FK_Projects_Languages_FromLanguageId",
table: "Projects",
column: "FromLanguageId",
principalTable: "Languages",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_Projects_Languages_ToLanguageId",
table: "Projects",
column: "ToLanguageId",
principalTable: "Languages",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
Error:
Failed executing DbCommand (17ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
ALTER TABLE [Projects] ADD CONSTRAINT [FK_Projects_Languages_FromLanguageId] FOREIGN KEY ([FromLanguageId]) REFERENCES [Languages] ([Id]) ON DELETE NO ACTION;
I am working on an ASP.NET Core project using code first I want to
alter database design. I have a case were I need to add two foreign
keys to the same table, even I used DeleteBehavior.Restrict, still the
error occurred when I update database
This is officially known issue. Because Primary keys are mapped by default convention please have a look here. You can't have single collection referenced by two FKs. Projects is mapped without cascading delete because it doesn't work in these self referencing many-to-many. Therefore, We have two ways to handle this scenario thus the error:
1. Change one or more of the relationships to not cascade delete.
In this scenario, we could make the Projects relationship with Languages optional by giving it a nullable foreign key property: for instance we can do something like:
.WillCascadeOnDelete(false);// Or you can try
.IsRequired(false)
Note: Either of one .WillCascadeOnDelete(false); or .IsRequired(false) should resolve your issue. You can check our official document for more details.
2. Configure the database without one or more of these cascade deletes,
then ensure all dependent entities are loaded so that EF Core can
perform the cascading behavior.
Considering this appreach we can keep the Projects, and Languages relationship required and configured for cascade delete, but make this configuration only apply to tracked entities, not the database: So we can do somethng like below:
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Projects>()
.HasOne(p => p.FromLanguage)
.WithMany(b => b.PFromLanguages)
.HasForeignKey(b => b.FromLanguageId)
.OnDelete(DeleteBehavior.Restrict);
.WillCascadeOnDelete(false);// Or .IsRequired(false)
builder.Entity<Projects>()
.HasOne(p => p.ToLanguage)
.WithMany(b => b.PToLanguages)
.HasForeignKey(b => b.ToLanguageId)
.OnDelete(DeleteBehavior.Restrict);
.WillCascadeOnDelete(false); // Or .IsRequired(false)
}
Note: As you may know OnDelete(DeleteBehavior.ClientCascade); or ClientCascade allows the DBContext to delete entities even if there is a cyclic ref or LOCK on it. Please read the official guideline for more details here . In addition, as you haven't share your detele operation code while, executing your project make sure you are also removing language from context like here.
The error occurred because I am trying to modify the relations between tables while there are some records already inserted into the targeted tables which violating new foreign key.
The solution was simply to clear existing records in those tables and then apply the migration..
Thank you all for your kind support.

Mapping-By-Code ignores Column Name in BagPropertyMapper

I'm encountering a problem, and I think it's an NHibernate defect.
My Database Schema, containing a simple Parent-Child mapping:
TABLE Company
(
ID BIGINT PRIMARY KEY
)
TABLE CompanyMailRecipient
(
ID BIGINT PRIMARY KEY IDENTITY(1, 1),
Company_ID BIGINT NOT NULL FOREIGN KEY REFERENCES Company(id),
Name VARCHAR(MAX),
EmailAddress VARCHAR(MAX),
DestinationType TINYINT
)
My classes. Note that the CompanyMailRecipient table has a column called EmailAddress, but my MailRecipient class has a column called Address.
public enum MessageDestinationType
{
Normal = 1,
CC = 2,
BCC = 3
}
public class MailRecipient
{
public virtual string Name {get; set }
public virtual string Address {get; set; } // Different name to the column!
public virtual MessageDestinationType DestinationType {get; set;}
}
public class MailConfiguration
{
private Lazy<IList<MailRecipient>> _recipients = new Lazy<IList<MailRecipient>>(() => new List<MailRecipient>());
public virtual IList<MailRecipient> Recipients
{
get
{
return _recipients.Value;
}
set
{
_recipients = new Lazy<IList<MailRecipient>>(() => value);
}
}
}
public class Company
{
public virtual long Id { get; set; }
public virtual MailConfiguration MailConfiguration { get; set; }
}
The mapping code
mapper.Class<Company>(
classMapper =>
{
classMapper.Table("Company");
classMapper.Component(
company => company.MailConfiguration,
componentMapper =>
{
componentMapper.Bag(mc => mc.Recipients,
bagPropertyMapper =>
{
bagPropertyMapper.Table("CompanyMailRecipient");
bagPropertyMapper.Key(mrKeyMapper =>
{
mrKeyMapper.Column("Company_Id");
});
},
r => r.Component(
mrc =>
{
mrc.Property
(
mr => mr.Name,
mrpm => mrpm.Column("Name")
);
/*****************************/
/* Here's the important bit */
/*****************************/
mrc.Property
(
mr => mr.Address,
mrpm => mrpm.Column("EmailAddress");
);
mrc.Property
(
mr => mr.DestinationType,
mrpm => mrpm.Column("DestinationType")
);
};
)
);
}
}
Now here's the problem: when I attempt to query a Company, I get the following error (with significant parts in bold)
NHibernate.Exceptions.GenericADOException : could not initialize a collection: [Kiosk.Server.Entities.Company.MailConfiguration.Recipients#576][SQL: SELECT recipients0_.Company_Id as Company1_0_, recipients0_.Name as Name0_, recipients0_.Address as Address0_, recipients0_.DestinationType as Destinat4_0_ FROM CompanyMailRecipient recipients0_ WHERE recipients0_.Company_Id=?]
----> System.Data.SqlClient.SqlException : Invalid column name 'Address'.
at NHibernate.Loader.Loader.LoadCollection(ISessionImplementor session, Object id, IType type)
But, if I change my C# code so my MailRecipient class has a propery called EmailAddress instead of Address, everything works.
It's like NHibernate is ignoring my column mapping.
Is this an NHibernate bug, or am I missing something?
The version of NHibernate I'm using is 4.0.4.4.
The example above has a one-to-many component hanging off a component that hangs off the entity.
I found that if I removed a layer of inderection, and had my one-to-many component hanging off the entity directly, then the column name takes effect.
Yes, this was indeed a bug in NHibernate.
I issued a fix as a pull request which has now been merged into the codebase. It should be in a release after 4.1.1.
Bug NH-3913
GitHub Commit

Fluent NHibernate - IndexOutOfRange

I've read all the posts and know that IndexOutOfRange usually happens because a column is being referenced twice. But I don't see how that's happening based on my mappings. With SHOW_SQL true in the config, I see an Insert into the Events table and then an IndexOutOfRangeException that refers to the RadioButtonQuestions table. I can't see the SQL it's trying to use that generates the exception. I tried using AutoMapping and have now switched to full ClassMap for these two classes to try to narrow down the problem.
public class RadioButtonQuestion : Entity
{
[Required]
public virtual Event Event { get; protected internal set; }
[Required]
public virtual string GroupIntroText { get; set; }
}
public class Event : Entity
{
[Required]
public virtual string Title { get; set; }
[Required]
public virtual DateTime EventDate { get; set; }
public virtual IList<RadioButtonQuestions> RadioButtonQuestions { get; protected internal set; }
}
public class RadioButtonQuestionMap : ClassMap<RadioButtonQuestion>
{
public RadioButtonQuestionMap()
{
Table("RadioButtonQuestions");
Id(x => x.Id).Column("RadioButtonQuestionId").GeneratedBy.Identity();
Map(x => x.GroupIntroText);
References(x => x.Event).Not.Nullable();
}
}
public class EventMap : ClassMap<Event>
{
public EventMap()
{
Id(x => x.Id).Column("EventId").GeneratedBy.Identity();
Map(x => x.EventDate);
Map(x => x.Title);
HasMany(x => x.RadioButtonQuestions).AsList(x => x.Column("ListIndex")).KeyColumn("EventId").Not.Inverse().Cascade.AllDeleteOrphan().Not.KeyNullable();
}
}
The generated SQL looks correct:
create table Events (
EventId INT IDENTITY NOT NULL,
EventDate DATETIME not null,
Title NVARCHAR(255) not null,
primary key (EventId)
)
create table RadioButtonQuestions (
RadioButtonQuestionId INT IDENTITY NOT NULL,
GroupIntroText NVARCHAR(255) not null,
EventId INT not null,
ListIndex INT null,
primary key (RadioButtonQuestionId)
)
This is using NH 3.3.0.4000 and FNH 1.3.0.727. When I try to save a new Event (with a RadioButtonQuestion attached) I see
NHibernate: INSERT INTO Events (EventDate, Title) VALUES (#p0, #p1);#p0 = 5/21/2012 12:32:11 PM [Type: DateTime (0)], #p1 = 'My Test Event' [Type: String (0)]
NHibernate: select ##IDENTITY
Events.Tests.Events.Tasks.EventTasksTests.CanCreateEvent:
NHibernate.PropertyValueException : Error dehydrating property value for Events.Domain.RadioButtonQuestion._Events.Domain.Event.RadioButtonQuestionsIndexBackref
----> System.IndexOutOfRangeException : An SqlCeParameter with ParameterIndex '3' is not contained by this SqlCeParameterCollection.
So if a column really is being referenced twice, what's the problem with my FNH config that's causing that behavior? I'm trying for a bidirection relationship (One Event Has Many Radio Button Questions) with ordering (I'll maintain it since NH won't in a bidir relationship, from what I've read). FWIW I also tried this as a unidirectional relationship by removing the Event from RadioButtonQuestion and it still caused the same exception.
I am using mapping in code (NH 3.3.1) and I have noticed that adding Update(false) and Insert(false) cures the problem:
ManyToOne(x => x.DictionaryEntity, map =>
{
map.Column("Dictionary");
map.Update(false);
map.Insert(false);
map.Cascade(Cascade.None);
map.Fetch(FetchKind.Select);
map.NotFound(NotFoundMode.Exception);
map.Lazy(LazyRelation.Proxy);
});
You have a bidirectional association, so one side should be marked as Inverse() and that can only be the RadioButtonQuestions collection. If you want the collection to be the owner, you have to remove the reference to the event in your RadioButtonQuestion class.
Additionally, the EventId column in the table RadioButtonQuestions is not nullable, which can cause problems, if the collection mapping is not inverse. See the note in the documentation.
I just spent a morning rooting this error out. The IndexOutOfRangeException sent me down the wrong path initially, but I've found the cause.
My problem concerned a FluentNHibernate class map that uses several components; the issue was that two properties were inadvertedly and incorrectly mapped to one and the same column:
before:
// example is stripped for simplicity, note the column names
Component(mappedClass => mappedClass.MappedComponent1,
map =>
{
map.Map(c => c.SomeProperty, "samecolumn");
});
Component(mappedClass => mappedClass.MappedComponent2,
map =>
{
map.Map(c => c.OtherProperty, "samecolumn");
});
after:
Component(mappedClass => mappedClass.MappedComponent1,
map =>
{
map.Map(c => c.SomeProperty, "firstcolumn");
});
Component(mappedClass => mappedClass.MappedComponent2,
map =>
{
map.Map(c => c.OtherProperty, "secondcolumn");
});
How this results in an IndexOutOfRangeException isn't obvious to me; I'm guessing that there's an array of mapped (source) properties and an array of destination columns, and in this case the destination array is too short for the number of items in the source properties array, because some of the destination columns are identical.
I think but it's worth writing a pull request for FluentNHibernate to check for this and throw a more explicit exception.

Set identity seed in fluentnhibernate

Using NHibernate you can set an identity seed like so:
<column name="Column1" not-null="true" sql-type="int IDENTITY(1,1000)"/>
The FluentNHibernate IdentityPart has CustomType and SqlCustomType methods, neither does it for me though. Is there a way to fluently set an identity seed?
More info:
When I do this: Map(x => x.Id).Column("CustomerId").CustomSqlType("int IDENTITY(1,1000)");
I get this error: The entity 'Customer' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
When I do this: Id(x => x.Id).Column("CustomerId").CustomSqlType("int IDENTITY(1,1000)");
I get this error: More than one column IDENTITY constraint specified for column 'CustomerId', table 'Customer'
Using FluentNHibernate 1.2.0.712.
I was able to duplicate that xml by doing something like this:
Map(x => x.LoginName, "Column1").CustomSqlType("int IDENTITY(1,1000)");
Edit:
If you can't achieve what you are wanting maybe you should explicitly map this using xml for now.
There is the article at the link below about implementing custom identity generator (see: Part 1: Inheriting from TableGenerator class) but the example throws the exception for SQLite database ("SQLite errorr no such table: hibernate_unique_key"). Thus as regard SQLite there is no possibility to gain current id key from a table. It uses class TableGenerator from NHibernate API (NHibernate.Id);
http://nhforge.org/wikis/howtonh/creating-a-custom-id-generator-for-nhibernate.aspx
To avoid the exception I implemented another solution (especially the way of getting current Id). It takes advantage of Fluent-NHibernate API (GeneratedBy.Custom()). Look at the following source code:
public class MyAutoincrement<T> : IIdentifierGenerator where T : IId
{
#region IIdentifierGenerator Members
public object Generate(ISessionImplementor session, object obj)
{
NHibernate.ISession s = (NHibernate.ISession)session;
int seedValue = 1000;
int maxId = -1;//start autoincrement from zero! (fluent nhibernate start from 1 as default)
List<T> recs = s.Query<T>().ToList<T>();
if (recs.Count > 0)
{
maxId = recs.Max(x => x.getId());
}
return seedValue + maxId + 1;
}
#endregion
}
//Interface for access to current Id of table
public interface IId
{
int getId();
}
//Entity
public class MyEntity : IId
{
public virtual int Id { get; protected set; }
public virtual string MyField1 { get; set; }
public virtual string MyField2 { get; set; }
#region IId Members
public virtual int getId()
{
return this.Id;
}
#endregion
}
//Entity Mapping
public class MyEntityMap : ClassMap<MyEntity>
{
public MyEntityMap()
{
Id(x => x.Id).GeneratedBy.Custom<MyAutoincrement<MyEntity>>();
Map(x => x.MyField1);
Map(x => x.MyField1);
}
}
It works with SQLite database and involves custom identity seed.
Regards
Bronek

Fluent NHibernate: Mapping HasManyToMany by convention

I'm using Fluent NHibernate's AutoMap feature to map my entities. Most of my entities inherit from a base class Entity which has a property public IList<Tag> Tags.
The tags are in a separate table in the database, so I use a many-to-many relation. But Fluent NHibernate creates mappings for a one-to-many relation.
I'd like to write a convention to override these mappings to use HasManyToMany(...) if the class inherits from Entity. Is this possible and how?
The convention could either rely on the property's type or its name.
Some code for illustration:
// entities
public class Entity
{
public virtual int Id { get; set; }
// ... some other properties
public virtual IList<Tag> { get; set; }
}
public class Tag
{
public virtual int Id { get; set; }
public virtual string TagName { get; set; }
}
public class Event : Entity
{
// ... some properties
}
// Fluent NHibernate configuration
public static ISessionFactory CreateSessionFactory()
{
var config = new CustomAutomappingConfiguration();
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("Sql")))
.Mappings(m =>
{
m.AutoMappings.Add(AutoMap.AssemblyOf<Event>(config)
.IgnoreBase<Entity>()
.Conventions.Add<CustomForeignKeyConvention>()
.Conventions.Add<CustomManyToManyTableNameConvention>();
})
.BuildSessionFactory();
}
I don't think you can accomplish the mapping with conventions. However, if you want to keep one linking table between the entities and tags, you can do the following:
m.AutoMappings.Add(AutoMap.AssemblyOf<Event>(config)
.IncludeBase<Entity>()
.Override<Entity>(map =>
map.HasManyToMany(e => e.Tags)
.Inverse()
.Cascade.SaveUpdate()));
Notice that I changed IgnoreBase<Entity>() to IncludeBase<Entity>(). This will add an Entity table, but will keep one linking table. With this mapping, you will get the following table DDL:
create table [Entity] (
Id INT IDENTITY NOT NULL,
primary key (Id)
)
create table TagToEntity (
Entity_id INT not null,
Tag_id INT not null
)
create table Event (
Entity_id INT not null,
primary key (Entity_id)
)
create table [Tag] (
Id INT IDENTITY NOT NULL,
TagName NVARCHAR(255) null,
primary key (Id)
)
alter table TagToEntity
add constraint FKD7554554A8C4CA9
foreign key (Tag_id)
references [Tag]
alter table TagToEntity
add constraint FKD75545564C9EC79
foreign key (Entity_id)
references [Entity]
alter table Event
add constraint FKA2FD7DF664C9EC79
foreign key (Entity_id)
references [Entity]
If you choose to do an Override<> per subclass, you will have a linking table per subclass.
In my case, I wanted to use an attribute to indicate a property that should participate in a many-to-many relationship where only one side of the relationship is declared. You could easily modify this to map by other conventions.
Many-to-many relationships are handled by FluentNHibernate.Automapping.Steps.HasManyToManyStep, an IAutomappingStep returned by the DefaultAutomappingConfiguration. This step will only map a property if it discovers a corresponding property of the related type (so both ends of the many-to-many relationship have to be declared).
The approach I've taken is to:
Create a decorator class for HasManyToManyStep that supports detecting and mapping many-to-many properties based on the presence of an attribute (or some other convention)
Create a class derived from DefaultAutomappingConfiguration to when automapping and override GetMappingSteps, wrapping any instance of HasManyToManyStep with the decorator
Here's the decorator, which tries to use the default HasManyToManyStep functionality first. Otherwise, if HasManyToManyAttribute is defined for the member, it will also create the relationship. The code used to create the relationship is nearly identical to the code used by HasManyToManyStep - just without reference to the other side of the relationship.
class ExplicitHasManyToManyStep : IAutomappingStep
{
readonly IAutomappingConfiguration Configuration;
readonly IAutomappingStep DefaultManyToManyStep;
public ExplicitHasManyToManyStep(IAutomappingConfiguration configuration, IAutomappingStep defaultManyToManyStep)
{
Configuration = configuration;
DefaultManyToManyStep = defaultManyToManyStep;
}
#region Implementation of IAutomappingStep
public bool ShouldMap(Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
return true;
}
//modify this statement to check for other attributes or conventions
return member.MemberInfo.IsDefined(typeof(HasManyToManyAttribute), true);
}
public void Map(ClassMappingBase classMap, Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
DefaultManyToManyStep.Map(classMap, member);
return;
}
var Collection = CreateManyToMany(classMap, member);
classMap.AddCollection(Collection);
}
#endregion
CollectionMapping CreateManyToMany(ClassMappingBase classMap, Member member)
{
var ParentType = classMap.Type;
var ChildType = member.PropertyType.GetGenericArguments()[0];
var Collection = CollectionMapping.For(CollectionTypeResolver.Resolve(member));
Collection.ContainingEntityType = ParentType;
Collection.Set(x => x.Name, Layer.Defaults, member.Name);
Collection.Set(x => x.Relationship, Layer.Defaults, CreateManyToMany(member, ParentType, ChildType));
Collection.Set(x => x.ChildType, Layer.Defaults, ChildType);
Collection.Member = member;
SetDefaultAccess(member, Collection);
SetKey(member, classMap, Collection);
return Collection;
}
void SetDefaultAccess(Member member, CollectionMapping mapping)
{
var ResolvedAccess = MemberAccessResolver.Resolve(member);
if (ResolvedAccess != Access.Property && ResolvedAccess != Access.Unset)
{
mapping.Set(x => x.Access, Layer.Defaults, ResolvedAccess.ToString());
}
if (member.IsProperty && !member.CanWrite)
{
mapping.Set(x => x.Access, Layer.Defaults, Configuration.GetAccessStrategyForReadOnlyProperty(member).ToString());
}
}
static ICollectionRelationshipMapping CreateManyToMany(Member member, Type parentType, Type childType)
{
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, childType.Name + "_id");
var Mapping = new ManyToManyMapping {ContainingEntityType = parentType};
Mapping.Set(x => x.Class, Layer.Defaults, new FluentNHibernate.MappingModel.TypeReference(childType));
Mapping.Set(x => x.ParentType, Layer.Defaults, parentType);
Mapping.Set(x => x.ChildType, Layer.Defaults, childType);
Mapping.AddColumn(Layer.Defaults, ColumnMapping);
return Mapping;
}
static void SetKey(Member property, ClassMappingBase classMap, CollectionMapping mapping)
{
var ColumnName = property.DeclaringType.Name + "_id";
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, ColumnName);
var Key = new KeyMapping {ContainingEntityType = classMap.Type};
Key.AddColumn(Layer.Defaults, ColumnMapping);
mapping.Set(x => x.Key, Layer.Defaults, Key);
}
}
HasManyToManyAttribute class, because there is no other convention I can easily rely on in my case:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class HasManyToManyAttribute : Attribute
{
}
Configuration class derived from DefaultMappingConfiguration class:
class AutomappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
return base.GetMappingSteps(mapper, conventionFinder).Select(GetDecoratedStep);
}
IAutomappingStep GetDecoratedStep(IAutomappingStep step)
{
if (step is HasManyToManyStep)
{
return new ExplicitHasManyToManyStep(this, step);
}
return step;
}
}