问题描述
使用NHibernate 5.2,由于执行以下操作时使用无效的密钥执行了错误的查询,因此我得到了ObjectNotFoundByUniqueKeyException
:
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);
}
已执行查询
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)]
我期望在最后两个查询中使用@p0 = 'joe'
,而不是1
和'1'
。谁能看到下面的映射问题来解释这种现象?
类/映射
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);
}
}
解决方法
使用雇员的主键不收集,而是另一个属性-PropertyRef
。而且我们必须告知一对多映射以及进行多对一映射
HasMany(x => x.Certifications)
.KeyColumn("UserId")
.Cascade.All()
// use property,not the ID,when searching for my items
.PropertyRef("UserId")
;
事实上,缺少此映射,导致在NHibernate加载集合时使用ID(魔术1)