Search code examples
nhibernatefluent-nhibernate

NHibernate using wrong key in queries, ObjectNotFoundByUniqueKeyException thrown


Using NHibernate 5.2, I'm getting an ObjectNotFoundByUniqueKeyException due to erroneous queries being executed with an invalid key when I do the following:

var session = sessionFactory.OpenSession();

var employee = new Employee(){
    UserId = "joe",
    Certifications = new List<Certification>()
};

employee.Certifications.Add(new Certification() { Employee = employee});

var id = session.Save(employee);
session.Flush();
session.Clear();
var emp = session.Get<Employee>(id);

foreach(var e in emp.Certifications)
{
    Console.WriteLine(e.Id);
}

Queries executed

NHibernate: INSERT INTO Employee (UserId) VALUES (@p0); select SCOPE_IDENTITY();@p0 = 'joe' [Type: String (4000:0:0)]
NHibernate: INSERT INTO Certification (UserId) VALUES (@p0); select SCOPE_IDENTITY();@p0 = 'joe' [Type: String (4000:0:0)]
NHibernate: SELECT userquery_0_.Id as id1_0_0_, userquery_0_.UserId as userid2_0_0_ FROM Employee userquery_0_ WHERE userquery_0_.Id=@p0;@p0 = 1 [Type: Int32 (0:0:0)]
NHibernate: SELECT certificat0_.UserId as userid2_1_1_, certificat0_.Id as id1_1_1_, certificat0_.Id as id1_1_0_, certificat0_.UserId as userid2_1_0_ FROM Certification certificat0_ WHERE certificat0_.UserId=@p0;@p0 = 1 [Type: Int32 (0:0:0)]
NHibernate: SELECT userquery_0_.Id as id1_0_0_, userquery_0_.UserId as userid2_0_0_ FROM Employee userquery_0_ WHERE userquery_0_.UserId=@p0;@p0 = '1' [Type: String (4000:0:0)]

I'm expecting @p0 = 'joe' in the final two queries, not 1 and '1'. Can anyone see a problem with the mappings below that would explain this behavior?

Classes / Mappings

public class Employee
{
    public virtual int Id { get; set; }
    public virtual string UserId { get; set; }
    public virtual ICollection<Certification> Certifications { get; set; }
}

public class EmployeeMap : ClassMap<Employee>
{
    public EmployeeMap()
    {
        Table("Employee");
        Id(x => x.Id);
        Map(x => x.UserId);
        HasMany(x => x.Certifications)
            .KeyColumn("UserId")
            .Cascade.All();
    }
}

public class Certification
{
    public virtual int Id { get; set; }
    public virtual Employee Employee { get; set; }
}

public class CertificationMap : ClassMap<Certification>
{
    public CertificationMap()
    {
        Table("Certification");
        Id(x => x.Id);
        References(x => x.Employee)
            .Column("UserId")
            .PropertyRef(x => x.UserId);
    }
}

Solution

  • Collection is not using primary key of Employee, it is another property instead - PropertyRef. And we must inform one-to-many mapping as well as we do for many-to-one

        HasMany(x => x.Certifications)
            .KeyColumn("UserId")
            .Cascade.All()
            // use property, not the ID, when searching for my items
           .PropertyRef("UserId")
           ;
    

    A fact, that this mapping was missing, was causing the ID to be used (the magic 1) when NHibernate was loading collection