Gini
Gini

Reputation: 96

Automapping doesn't have an Id mapped

My Entity Class:
public class Building 
    {
        /// <summary>
        /// internal Id 
        /// </summary>
        public virtual long Id { get; set; }
..............
}

My Mapping:

var model = AutoMap.AssemblyOf<Building>()
                        .Setup(s => s.FindIdentity = p => p.Name == "Id")
                        .Where(t => t.Namespace == "SpikeAutoMappings");

var database = Fluently.Configure()
                        .Database(DatabaseConfigurer)
                        .Mappings(m=>m.AutoMappings.Add(model));

I need somebody to help me see what is wrong because I keep having this error when run unit test:

Initialization method TestProject1.MappingTestBase.TestInitialize threw exception. FluentNHibernate.Cfg.FluentConfigurationException:  FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.

 --->  FluentNHibernate.Visitors.ValidationException: The entity doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id)..

Upvotes: 3

Views: 9130

Answers (3)

user598320
user598320

Reputation: 21

Generally, using AutoMapping is a poor policy because the filed Id must exist in your database tables. Instead, consider using a fluent mapping generator, such as NMG to handle your mapping.

In this case, you would first want to download/install the application, then generate the Mapping Files from your database (Oracle, SQL and various others).

In order to create the Mapping Files, first create an /Entities/ folder within your project. Next, configure the generator software as follows:

Preferences

  1. Generated Property Name = Same as database column name (No change)
  2. Mapping Style = Fluent Mapping
  3. Field or Property = Auto Property

Languages available: C# and VB

  1. Folder : [your project folder]\Entities
  2. Namespace : [your project namespace].Entities
  3. Assembly Name: [your project name].Entities

Next, either Generate All or Generate the Specific Table.

All of the *.cs and *Map.cs files should now be created in your project (you can add them with Add Existing Item... if they don't show up).

Using Fluent, you will see something like the following:

Id(x => x.keyName_ID)
  .Column(x => x.keyname_ID)
  .GeneratedBy
  .Sequence("keyname_ID")

or

Id(x => x.keyName_ID)
  .Column(x => x.keyname_ID)
  .GeneratedBy
  .Identity()
  .Column("keyname_ID")

or

Id(x => x.keyName_ID)
  .Column(x => x.keyname_ID)
  .GeneratedBy
  .Assigned()

So, now we need to specify the Id using FluentMapping with Fluent nHibernate. To do this, you need to overwrite the Id line of on code in each of the Map files in the solution. Simply add:

Id(x => x.KeyName_ID)
  .GeneratedBy
  .GetGeneratorMapping()
  .IsSpecified("KeyName_ID");

Where keyname_id is the column name of the id in your database, rather than the one created.

Notice that in your mapping at the BuildSession you must have:

(...).Mappings(m => 
    m.FluentMappings.AddFromAssemblyOf<[one of your entities]>()
);

And, now Id is mapped. :) I hope this helps!

Upvotes: 2

J. Ed
J. Ed

Reputation: 6742

both answers above are right; unless you specify differently, the automapper assumes that you have an int Id field.
If your Id is long, the automapper might not recognize it correctly.
try defining a MappingOverride for your class(es), like so:

public class UserMappingOverride : IAutoMappingOverride<User>
{
    #region IAutoMappingOverride<User> Members

    public void Override(AutoMapping<User> mapping)
    {
        mapping.Id(u => u.Name);
    }

    #endregion
}

the Id() function allows you to override the automapper's convention of what the ID field should be.
for further info on overriding, see http://wiki.fluentnhibernate.org/Auto_mapping#Overrides.
Cheers,
Jhonny

Upvotes: 9

Tom Bushell
Tom Bushell

Reputation: 5875

My experience with Automapping is that as long as your Entity class has the line:

    public virtual int Id { get; private set; }

the automapper will treat it as an ID with no further help from the programmer (i.e. no need for the FindIdenity code you are using in your AutoMap call).

The only difference I see in your ID declaration is that you use a type long instead of int. Don't know if this matters or not.

Upvotes: 0

Related Questions