1
votes

I've been trying to map two objects using a one-to-one bi-directional relationship. The relationship between the two objects is not required. Here are the objects:

public class Tenant
{
    public virtual int TenantId { get; set; }

    public virtual string Name { get; set; }

    public virtual Unit Unit { get; set; }
}

public class Unit
{
    public virtual int UnitId { get; set; }

    public virtual string UnitNumber { get; set; }

    public virtual int Rooms { get; set; }

    public virtual Tenant Tenant { get; set; }
}

And here are the mappings I'm trying to use:

public class Mappings : ClassMap<Unit>
{

    /*
     * Unit
     * ------------
     * UnitId (PK)
     * TenantId (FK)
     * Rooms
     * UnitNumber
     */

    public Mappings()
    {
        Id(x => x.UnitId).GeneratedBy.Identity();

        References(x => x.Tenant);

        Map(x => x.Rooms).Not.Nullable();
        Map(x => x.UnitNumber).Not.Nullable();
    }
}



public class TenantMapping : ClassMap<Tenant>
{
    /*
     * Tenant
     * -------------
     * TenantId (PK)
     * Name 
     */
    public TenantMapping()
    {
        Id(x => x.TenantId).GeneratedBy.Identity();

        Map(x => x.Name).Not.Nullable();

        HasOne(x => x.Unit).PropertyRef(x => x.Tenant);
    }
}

The expected table definitions are in the mapping comments. The tests that I'm using to verify the mappings are failing:

    [Test]
    public void SetTenantOnUnit()
    {
        int unitId = 0;
        int tenantId = 0;
        using (var session = factory.OpenSession())
        {
            var tenants = Builder<Tenant>.CreateListOfSize(5).Build();
            var unit = Builder<Unit>.CreateNew().Build();
            foreach(var tenant in tenants)  
                session.Save(tenant);

            session.Save(unit);

            unit.Tenant = tenants[3];
            tenantId = unit.Tenant.TenantId;
            session.SaveOrUpdate(unit);

            unitId = unit.UnitId;
        }

        using (var session = factory.OpenSession())
        {
            var unit = session.Get<Unit>(unitId);
            Assert.That(unit, Is.Not.Null);
            Assert.That(unit.Tenant, Is.Not.Null);
            Assert.That(unit.Tenant.TenantId, Is.EqualTo(tenantId), "Incorrect Tenant Id");
        }

    }

    [Test]
    public void SetUnitOnTenant()
    {
        int tenantId = 0;
        int unitId = 0;
        using (var session = factory.OpenSession())
        {
            var tenant = Builder<Tenant>.CreateNew().Build();
            var units = Builder<Unit>.CreateListOfSize(5).Build();
            session.Save(tenant);

            foreach(var unit in units)
                session.Save(unit);


            tenant.Unit = units[3];
            unitId = tenant.Unit.UnitId;

            session.SaveOrUpdate(tenant);
            tenantId = tenant.TenantId;
        }

        using (var session = factory.OpenSession())
        {
            var tenant = session.Get<Tenant>(tenantId);
            Assert.That(tenant, Is.Not.Null);
            Assert.That(tenant.Unit, Is.Not.Null);
            Assert.That(tenant.Unit.UnitId, Is.EqualTo(unitId), "Incorrect unit id");
        }
    }

I've included the source code here: https://bitbucket.org/crmckenzie/fluentnhibernate.discovery/overview

Ideally, I'd be able to create the relationship from either side and have it save successfully to the database. I've read the other one-to-one mapping topics on StackOverFlow, and none of them seem to be directly on point. How can I map this relationship correctly?

1

1 Answers

0
votes

your are missing a session.Flush(); after unitId = unit.UnitId; and tenantId = tenant.TenantId; hence the assignement is not saved in db. The reason why the tenants and units are saved is that you force NHibernate to insert immediatly on session.Save(). Since you set GeneratedBy.Identity() nhibernate has to ask the database for the id, otherwise unitId = unit.UnitId; would yield the wrong result.