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; }
}
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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With