NHibernate:保存临时实例时如何更新身份ID?
如果我使用每事务会话并调用:
session.SaveOrUpdate(entity) 更正:
session.SaveOrUpdateCopy(entity)
..实体是一个identity-Id=0的瞬态实例。上面的行是否会自动更新实体的Id,并使实例持久化?或者应该在 transaction.Commit 上这样做?或者我是否必须以某种方式明确编码?
显然,数据库行的 ID(新的,因为瞬态)是自动生成的并保存为某个数字,但我在这里讨论的是实际的参数实例。这是业务逻辑实例。
编辑 - 相关问题的后续行动。
映射:
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
HasMany(x => x.Staff) // 1:m
.Cascade.All();
HasManyToMany(x => x.Products) // m:m
.Cascade.All()
.Table("StoreProduct");
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.FirstName);
Map(x => x.LastName);
References(x => x.Store); // m:1
}
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name).Length(20);
Map(x => x.Price).CustomSqlType("decimal").Precision(9).Scale(2);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table("StoreProduct");
}
}
EDIT2
类定义:
public class Store
{
public int Id { get; private set; }
public string Name { get; set; }
public IList<Product> Products { get; set; }
public IList<Employee> Staff { get; set; }
public Store()
{
Products = new List<Product>();
Staff = new List<Employee>();
}
// AddProduct & AddEmployee is required. "NH needs you to set both sides before
// it will save correctly"
public void AddProduct(Product product)
{
product.StoresStockedIn.Add(this);
Products.Add(product);
}
public void AddEmployee(Employee employee)
{
employee.Store = this;
Staff.Add(employee);
}
}
public class Employee
{
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Store Store { get; set; }
}
public class Product
{
public int Id { get; private set; }
public string Name { get; set; }
public decimal Price { get; set; }
public IList<Store> StoresStockedIn { get; private set; }
}
If I use session-per-transaction and call:
session.SaveOrUpdate(entity) corrected:
session.SaveOrUpdateCopy(entity)
..and entity is a transient instance with identity-Id=0. Shall the above line automatically update the Id of the entity, and make the instance persistent? Or should it do so on transaction.Commit? Or do I have to somehow code that explicitly?
Obviously the Id of the database row (new, since transient) is autogenerated and saved as some number, but I'm talking about the actual parameter instance here. Which is the business logic instance.
EDIT - Follow-up, of related problem.
Mappings:
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name);
HasMany(x => x.Staff) // 1:m
.Cascade.All();
HasManyToMany(x => x.Products) // m:m
.Cascade.All()
.Table("StoreProduct");
}
}
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.FirstName);
Map(x => x.LastName);
References(x => x.Store); // m:1
}
}
public class ProductMap : ClassMap<Product>
{
public ProductMap()
{
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.Name).Length(20);
Map(x => x.Price).CustomSqlType("decimal").Precision(9).Scale(2);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table("StoreProduct");
}
}
EDIT2
Class definitions:
public class Store
{
public int Id { get; private set; }
public string Name { get; set; }
public IList<Product> Products { get; set; }
public IList<Employee> Staff { get; set; }
public Store()
{
Products = new List<Product>();
Staff = new List<Employee>();
}
// AddProduct & AddEmployee is required. "NH needs you to set both sides before
// it will save correctly"
public void AddProduct(Product product)
{
product.StoresStockedIn.Add(this);
Products.Add(product);
}
public void AddEmployee(Employee employee)
{
employee.Store = this;
Staff.Add(employee);
}
}
public class Employee
{
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Store Store { get; set; }
}
public class Product
{
public int Id { get; private set; }
public string Name { get; set; }
public decimal Price { get; set; }
public IList<Store> StoresStockedIn { get; private set; }
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
就您的问题而言,每当刷新会话时,实体就会持久保存到数据库中。保存您的(新)实体时,NHibernate 使用您提供的生成器为您生成 ID。
请记住,不建议使用身份生成器(请参阅 Ayende 的这篇文章)。
当您使用身份生成器时,即使您没有刷新到数据库,您的新实体也会在保存时持久保存到数据库中。发生这种情况的原因是 NHibernate 需要为您提供实体的 ID,如果不与数据库进行往返,它就无法做到这一点。
更好的解决方案是使用 Guid 生成器之类的东西,或者如果您想要“正常”值,则使用 HiLo。通过这种方式,您可以保存实体,而无需实际进行数据库往返,这使您可以提高性能(想到批处理)。
As far as your question is concerned, whenever you flush your session is when your entity is persisted to the database. When saving your (new) entity, NHibernate generates the ID for you using the generator you provided.
Keep in mind that an Identity generator is not recommended (see this post by Ayende).
When you use an Identity generator, your new entity is persisted to the database when you save, even if you don't flush to the database. The reason this happens is because NHibernate needs to provide you with an ID for the entity, which it can't do without doing a roundtrip to the database.
A better solution would be to use something like a Guid generator, or HiLo if you want 'normal' values. This way you can save your entity without actually having to do a database roundtrip, which allows you to do a lot more performance wise (batching comes to mind).
我不确定我是否理解你的问题。实际保存到数据库是在刷新会话时(例如通过提交事务)。调用 SaveOrUpdate() 本身并不保存实体,它只是通知会话在刷新会话时将保存该实体。
假设实体的ID映射到数据库中的一个身份字段,并且您的映射告诉NHibernate身份是由数据库设置的,那么数据库设置的ID将在保存时设置为实体的ID。
I'm not sure I understand your question. The actual saving to the database occurs when the session is flushed (e.g. by committing the transaction). Calling SaveOrUpdate() doesn't itself save the entity, it just informs the session that the entity is due to be saved when the session is flushed.
Assuming that the ID of the entity maps to an identity field in the database and that your mapping tells NHibernate that identity is set by the database, then the ID set by the database will be set as the entity's ID when it is saved.
Nhibernate 将在 SaveOrUpdate 调用之后设置实体的 ID 属性。
Nhibernate will set the ID property of your entity just after SaveOrUpdate call.
我注意到我通过调用保存:
..这不会更新 ID。但通过更改为:
..瞬态实体的 ID将更新。
我可能误解了文档(?)..第 9.4 节。 2 表示:
SaveOrUpdateCopy(Object o)...如果给定实例未保存或数据库中不存在,NHibernate 将保存它并将其作为新的持久实例返回。
只是我一个人,还是听起来不像一个瞬态对象(未保存),将“作为持久性返回”?这不是意味着更新了ID吗?希望能澄清如何正确解释这句话(?)
I noticed I saved by calling:
..which does NOT update the Id. But by changing to:
..the Id's of transient entity will be updated.
I probably misunderstood the documentation (?).. Section 9.4.2 says:
SaveOrUpdateCopy(Object o)... If the given instance is unsaved or does not exist in the database, NHibernate will save it and return it as a newly persistent instance.
Is it just me, or does it not sound like a transient object (unsaved), will be "returned as persistent" ? Doesn't that mean with updated Id? Would appreciate a clarification how to interpret this sentence correctly (?)