如何在 NHibernate 中的 INSERT 之后启用延迟加载关系
How to enable lazy loading of relations after INSERT in NHibernate
我在 NHibernate 中的两个实体之间有一个一对多的关系:
public class Application
{
public string TaskId { get; set; } // Foreign key reference
public Task Task { get; set; } // The relation/navigation property
}
db.Web.Applications.Create
方法只是在一个事务中调用NHibernate会话的"SaveOrUpdate"方法。
相关映射:
internal class ApplicationMap : ClassMap<Application>
{
public ApplicationMap() : base()
{
Schema(...);
Table(...);
CompositeId()
.KeyProperty(app => app.UserId, "...")
.KeyProperty(app => app.TaskId, "task_id")
.KeyProperty(app => app.TransactionId, "...");
// Relations
References(app => app.Task, "task_id")
.ForeignKey("taskid")
.Unique()
.Not.Insert()
.Cascade.Persist();
}
}
internal class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Schema(..);
Table(...);
Id(task => task.Id, "task_id");
HasMany(task => task.Applications)
.KeyColumn("task_id");
}
}
当我针对真实数据库编写测试以创建新的 Application
时,我发现导航 属性 在插入后没有延迟加载:
var app = new Application(...)
{
TaskId = "..."
};
db.Web.Applications.Create(app);
db.SaveChanges();
var actual = db.Web.Applications.Find(app.UserId, app.TaskId, app.TransactionId);
// actual.Task is null
映射工作如我所料,但是在插入新的 Application
对象后,访问 Task
属性 returns null
而不是惰性从数据库加载该实体。这可以做到吗?如果可以,怎么做?
我认为您的问题出在映射 Application
class 及其对应的 Task
对象关系的方式上。我认为你应该这样映射它:
public class Application
{
public Task Task { get; set; } // The relation/navigation property
}
internal class ApplicationMap : ClassMap<Application>
{
public ApplicationMap() : base()
{
Schema(...);
Table(...);
CompositeId()
.KeyProperty(app => app.UserId, "...")
.KeyReference(app => app.Task, "task_id")
.KeyProperty(app => app.TransactionId, "...");
}
}
internal class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Schema(..);
Table(...);
Id(task => task.Id, "task_id");
HasMany(task => task.Applications)
.KeyColumn("task_id");
}
}
不需要为外键关系映射特定的 ID 属性。我总是只映射实体。这样就容易多了。那么你上面的插入代码将是这样的:
var app = new Application(...)
{
Task = session.Load<Task>(taskId)
};
db.Web.Applications.Create(app);
db.SaveChanges();
var actual = db.Web.Applications.Find(app.UserId, app.TaskId, app.TransactionId);
我在 NHibernate 中的两个实体之间有一个一对多的关系:
public class Application
{
public string TaskId { get; set; } // Foreign key reference
public Task Task { get; set; } // The relation/navigation property
}
db.Web.Applications.Create
方法只是在一个事务中调用NHibernate会话的"SaveOrUpdate"方法。
相关映射:
internal class ApplicationMap : ClassMap<Application>
{
public ApplicationMap() : base()
{
Schema(...);
Table(...);
CompositeId()
.KeyProperty(app => app.UserId, "...")
.KeyProperty(app => app.TaskId, "task_id")
.KeyProperty(app => app.TransactionId, "...");
// Relations
References(app => app.Task, "task_id")
.ForeignKey("taskid")
.Unique()
.Not.Insert()
.Cascade.Persist();
}
}
internal class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Schema(..);
Table(...);
Id(task => task.Id, "task_id");
HasMany(task => task.Applications)
.KeyColumn("task_id");
}
}
当我针对真实数据库编写测试以创建新的 Application
时,我发现导航 属性 在插入后没有延迟加载:
var app = new Application(...)
{
TaskId = "..."
};
db.Web.Applications.Create(app);
db.SaveChanges();
var actual = db.Web.Applications.Find(app.UserId, app.TaskId, app.TransactionId);
// actual.Task is null
映射工作如我所料,但是在插入新的 Application
对象后,访问 Task
属性 returns null
而不是惰性从数据库加载该实体。这可以做到吗?如果可以,怎么做?
我认为您的问题出在映射 Application
class 及其对应的 Task
对象关系的方式上。我认为你应该这样映射它:
public class Application
{
public Task Task { get; set; } // The relation/navigation property
}
internal class ApplicationMap : ClassMap<Application>
{
public ApplicationMap() : base()
{
Schema(...);
Table(...);
CompositeId()
.KeyProperty(app => app.UserId, "...")
.KeyReference(app => app.Task, "task_id")
.KeyProperty(app => app.TransactionId, "...");
}
}
internal class TaskMap : ClassMap<Task>
{
public TaskMap()
{
Schema(..);
Table(...);
Id(task => task.Id, "task_id");
HasMany(task => task.Applications)
.KeyColumn("task_id");
}
}
不需要为外键关系映射特定的 ID 属性。我总是只映射实体。这样就容易多了。那么你上面的插入代码将是这样的:
var app = new Application(...)
{
Task = session.Load<Task>(taskId)
};
db.Web.Applications.Create(app);
db.SaveChanges();
var actual = db.Web.Applications.Find(app.UserId, app.TaskId, app.TransactionId);