Question

I'm configuring mapping with Fluent NHibernate.

So, I Have a component defined as follow:

public class Tracking
{
    public virtual string CreatedBy { get; set; }
    public virtual DateTime CreatedOn { get; set; }
    public virtual string UpdatedBy { get; set; }
    public virtual DateTime UpdatedOn { get; set; }
    public virtual string DeletedBy { get; set; }
    public virtual DateTime DeletedOn { get; set; }

    public Tracking()
    {
        CreatedBy = Environment.UserName;
        UpdatedBy = Environment.UserName;
    }
}

Which is mapped using the following mapping:

class TrackingMap : ComponentMap<Tracking>
{
    public TrackingMap()
    {
        Map(c => c.CreatedBy);
        Map(c => c.CreatedOn);
        Map(c => c.UpdatedBy);
        Map(c => c.UpdatedOn);
        Map(c => c.DeletedBy);
        Map(c => c.DeletedOn);
    }
}

Then, I have another class that references the component:

public class Mission
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Tracking Tracking { get; set; }
}

With the corresponding mapping:

class MissionMap : ClassMap<Mission>
{
    public MissionMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Component(x => x.Tracking);
    }
}

My problem When I build the session factory, I have a FluentConfigurationException with the message

Multiple external components for 'Tracking', referenced from property 'Tracking' of 'Mission', unable to continue.

However, when I use inline mapping:

class MissionMap : ClassMap<Mission>
{
    public MissionMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Component(x => x.Tracking, m =>
        {
            m.Map(c => c.CreatedBy);
            m.Map(c => c.CreatedOn);
            m.Map(c => c.UpdatedBy);
            m.Map(c => c.UpdatedOn);
            m.Map(c => c.DeletedBy);
            m.Map(c => c.DeletedOn);
        });
    }
}

It works just well.

Any help will be greatly appreciated.

Was it helpful?

Solution

Actually your code works fine for me with the following test and some slight modifications to be able to persist the objects...

Are you sure you did not leave your old code uncommented somewhere in the same assembly? The exception will be thrown only if you there are more then one provider (mapping) available for one entity. This means the map for Tracking is also defined somewhere else...

Some test setup:

var sessionFactory = Fluently.Configure()
    .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2000
        .ConnectionString(@"Server=.\SQLExpress;Database=TestDB;Trusted_Connection=True;")
        .ShowSql)
    .Mappings(m => m.FluentMappings
        .AddFromAssemblyOf<MissionMap>())
    .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true))
    .BuildSessionFactory();

using (var session = sessionFactory.OpenSession())
{
    var rr = session.Get<Mission>(1);
    if (rr == null) {
        var mission = new Mission()
        {
            Name = "some name",
            Tracking = new Tracking()
        };
        session.Save(mission);
    }
    if (rr != null)
    {
        rr.Tracking.UpdatedBy = "me";
        rr.Tracking.UpdatedOn = DateTime.Now;
        session.Update(rr);
    }
    //if (rr != null)
    //{
    //    session.Delete(rr);
    //}
    session.Flush();
}

Changed Entities

public class Tracking
{
    public virtual int Id { get; set; }
    public virtual string CreatedBy { get; set; }
    public virtual DateTime CreatedOn { get; set; }
    public virtual string UpdatedBy { get; set; }
    public virtual DateTime UpdatedOn { get; set; }
    public virtual string DeletedBy { get; set; }
    public virtual DateTime? DeletedOn { get; set; } // deletedon should be nullable

    public Tracking()
    {
        CreatedBy = Environment.UserName;
        CreatedOn = DateTime.Now;
        UpdatedBy = Environment.UserName;
        UpdatedOn = DateTime.Now;
    }
}

public class Mission
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Tracking Tracking { get; set; }
}

class MissionMap : ClassMap<Mission>
{
    public MissionMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        Component(x => x.Tracking);
    }
}

class TrackingMap : ComponentMap<Tracking>
{
    public TrackingMap()
    {
        Map(c => c.CreatedBy);
        Map(c => c.CreatedOn);
        Map(c => c.UpdatedBy);
        Map(c => c.UpdatedOn);
        Map(c => c.DeletedBy);
        Map(c => c.DeletedOn);
    }
}

This will store the Tracking data into the same table as Mission data (which is the intention of Component).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top