StaleStateException when changing id in nhibernate - nhibernate

Very new to NHibernate so I expect there will be a quick fix here.
The code I'm looking at has an unorthodox design.
public class Partner
{
public virtual int Id { get; set;} //note the set is not private
public virtual String Name { get; set;}
}
and is mapped with FluentNhibernate's Automappings
When Partner is created its Id is 0 but when
I call Flush to persist to the db:
CurrentSession.SaveOrUpdate(obj);
CurrentSession.Flush();
I get a Unexpected row count: 0; expected: 1 StaleStateException
I'm assuming its because NHibernate doesn't like me changing the Primary Key, Id.
In this case I need to. How can I configure NH to let me achieve this abomination?

You can do the update with HQL:
session.CreateQuery("update Partner set Id = :newId where Id = :oldId")
.SetParameter("newId", newId)
.SetParameter("oldId", oldId)
.ExecuteUpdate();
I suggest that you Evict the entity from the session, or use a stateless one if you are going to update the Id.

Related

NHibernate Proxy Id Value

Seeing a scenario where upon loading an entity by id, NH is loading via proxy (which is expected), however, backing fields for id = 0, but virtual property (getter), is the id of the entity from the db.
Example:
private int _id;
public virtual int Id { get { return _id; } }
and mapping
...
<id name="Id" access="nosetter.camelcase-underscore">
...
Upon loading the entity, the _id = 0, but Id = 4 for example.
Is it normal behaviour for the backing fields to not be initialised while entity is proxied?
I would say: do not worry. There is nothing wrong. And it is normal behaviour.
You can try to create another property, e.g.
public virtual int MyTestId
{
get { return _id + 1; }
}
And you'll see that MyTestId is 5 (to continue the case study above, when the Id == 4). Simply, you've most likely faced the VS debugger... which is just a human.

Creating a map for relationship key besides using object property

I have a Note class which has a relationship through Client class, and therefore has a property
public virtual Client Client {get; set;}
but how can I add a map to the client_id column, for example having
public virtual int? ClientId {get; set;}
You don't.
If you need to get the value of the FK, you can just do this:
var clientId = note.Client == null? (int?)null : note.Client.Id;
Accessing the id will not cause loading of the Client proxy.
If you need to set the value (and you have an id):
note.Client = session.Load<Client>(clientId);
In the mapping class you would have:
Map(x => x.ClientId);

Is there something analogous on NHibernate regarding Entity Framework's navigation property?

Is there something analogous on NHibernate regarding Entity Framework's navigation property? For example, instead of:
s.Save(new Product { Category = s.Get<Category>("FD"), Name = "Pizza" });
I wish I could write:
s.Save(new Product { CategoryId = "FD", Name = "Pizza" });
Can I inform NHibernate not to use the Product's Category property as a mechanism to save the Product's category? I want to use CategoryId instead(Read: I don't want to use DTO). Entity Framework seems able to facilitate avoiding DTO patterns altogether, while at the same time offering the full benefit of ORM(can avoid joins using navigation properties). I want the EF's offering the best of both worlds(lean mechanism for saving objects, i.e. no need to retrieve the property's object) and navigation mechanism for querying stuff
Sample from EF: http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-code-first-walkthrough.aspx
public class Category
{
public virtual string CategoryId { get; set; }
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
}
public class Product
{
public virtual int ProductId { get; set; }
public virtual string Name { get; set; }
public virtual string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
[UPDATE]
Regarding James answer, I tried seeing the NHibernate's actions in SQL Server Profiler.
// this act didn't hit the Category table from the database
var c = s.Load<Category>("FD");
// neither this hit the Category table from the database
var px = new Product { Category = c, Name = "Pizza" };
// this too, neither hit the Category table from the database
s.Save(px);
Only when you actually access the Category object that NHibernate will hit the database
Console.WriteLine("{0} {1}", c.CategoryId, c.Name);
If I understand your question, you want to save a Product with a Category without hitting the database to load the Category object. NHibernate absolutely supports this and you almost have the right code. Here is how you do it in NHibernate:
s.Save(new Product { Category = s.Load<Category>("FD"), Name = "Pizza" });
This will not hit the database to fetch the actual Category, but it will simply save a Product with the correct Category.Id. Note that you don't need (and I would recommend getting rid of Product.CategoryId).
Now why does this work with session.Load(), but not session.Get()... With session.Get(), NHibernate has to return the object or null. In .NET, there is no way for an object to replace itself with null after the fact. So NHibernate is forced to go to the database (or L1 cache) to verify that the "FD" Category actually exists. If it exists, it returns an object. If not, it must return null.
Let's look at session.Load(). If the object is not present in the database, it throws an exception. So NHibernate can return a proxy object from session.Load() and delay actually hitting the database. When you actually access the object, NHibernate will check the database and can throw an exception at that point if the object doesn't exist. In this case, we're saving a Product to the database. All NHibernate needs is the Category's PK, which it has in the proxy. So it doesn't have to query the database for the Category object. NHibernate never actually needs to hydrate an actual Category object to satisfy the save request.

in fluent-nhibernate,saving a many-to-one entity, why i should give a version to the referenced entity

i have the following entities:
public class Worker
{
public int WorkerID {get;set;}
public string Name { get;set;}
public int version { get;set;}
}
public class TransferOrder
{
public int TransferOrderID { get;set;}
public Worker workerTobeTransfered{get;set;}
public int version { get;set;}
}
and i am using the Auto mapping, in fluent nhibernate.
when i try to save the TransferOrder like this:
TransferOrder order = new TransferOrder();
order.Worker = new Worker(){WorkerID = 1};
Session.Save(order);
but in database, the workerID in the TransferOrder table is NULL???
but when i give a version to the worker, it is saved as normal?
TransferOrder order = new TransferOrder();
order.Worker = new Worker(){WorkerID = 1,Version = 1};
Session.Save(order);
notice that it is not important what version number is given to the worker as long as it is not 0.
and i have a worker saved in the database with workerID = 1.
how can i handle this ? why should i give a version to the worker???is the nhibernate making sure that worker is saved?? and why it should do that ?
Maybe this is the scenerio:
Your Work.WorkerID is an identity column within your Work table and, you cannot insert a row into your table that consists of only an identity column entry.
But when you provide a value for Work.Version, as well, then you are creating a valid insert.
The "version" is probably going to be auto mapped to a NHibernate attribute for optimistic concurrency checking. I would use Fluent NHibernate to generate the mapping XML to see what it's using, as I can't find anything via Google about the default settings for auto mapped .

NHibernate one way, one-to-many, mapping question

I have a scenario in NHibernate where I have a one-to-many relationship between entities Employee and EmployeeStatus.
Employee has properties eg: ID, Name and an IList of EmployeeStatus, whilst EmployeeStatus, for the purposes of this question, just has it's own ID and some free text.
I don't need to hold a reference to Employee from EmployeeStatus, the management of status' will be done purely through the Employee entity - adding to the IList property. IE: I want to quite simply be able to do the following;
Employee e = new Employee();
e.Name = "Tony";
e.StatusList.Add( new EmployeeStatus("Status A") );
e.StatusList.Add( new EmployeeStatus("Status B") );
session.Save(e);
I've tried various methods, including creating a one way one-to-many mapping where inverse is false, cascade set to all-delete-orphan, which all looks like it should work, but it generates an exception about being unable to set the EmployeeId in EmployeeStatus. I'm led to believe that this is because NHibernate wants to do an insert with EmployeeId as NULL and then update it to the ID of the parent.
I guess I'm missing something here, so quite simply - can anyone tell me what my mapping file should look like to achieve the above?
Thanks in advance
Tony
-- edit: Heres a rough idea of the classes as requested --
public class Employee
{
private IList<EmployeeStatus> _statusList;
public Employee()
{
_statusList = new List<EmployeeStatus>();
}
public virtual int Id{ get; set; }
public virtual string Name{ get; set; }
public virtual IList<EmployeeStatus> StatusList
{
get
{
return _statusList;
}
}
}
public class EmployeeStatus
{
public virtual int Id{ get; set; }
public virtual string StatusText{ get; set; }
public EmployeeStatus()
{
}
public EmployeeStatus(string statusText)
{
StatusText = statusText;
}
}
The scenario you've described is just a basic one-to-many mapping. Here is the Fluent NHibernate mapping for this:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
WithTable("Employee");
HasMany(employee => employee.StatusList)
.Cascade.All();
}
}
You do not need to maintain a reference from EmployeeStatus back to Employee to achieve this.
Turns out that what I want to do isn't possible - you have to have a bi-directional association, and must set the child's parent reference. Not a massive problem I suppose, but didn't want to hold references in the child that I don't need within my code directly.
I may not of explained clearly, but an employee status cannot be linked to more than one employee. It's definitely 1 (employee) to many (status')
In the physical database, the status entity has an employeeID field, which isn't in the domain - IE: I hold no reference back to employee from the status entity, but the physical field should be inferred from the owner of the collection - In fact, it does do this if I set the EmployeeID field in the status table to nullable - it actually executes 2 SQL statements - an insert and then an update, the EmployeeID being set in the update.
Thanks,
Tony
Can you post the code for the classes?
Are you trying to keep a history of statuses for an Employee?
-- Edit --
Looks like you are going to need many-to-many, since the child in the relationship (EmployeeStatus) has no reference back to the parent (Employee).
-- Edit 2 --
If you want the insert to be done as 1 call to the DB, you are going to need to add an Employee property to the EmployeeStatus class, and set the Inverse=true. And I'm pretty sure that you are going to need to add some logic which sets the bi-directional relationship in the objects. I.E.
public void AddStatus(EmployeeStatus status)
{
this.StatusList.Add(status);
status.Employee = this;
}