Reputation: 681
I have an object that is saved using Nhibernate. This object use a composite key and is declared like this :
CompositeId()
.KeyProperty(x => x.CreditorName)
.KeyProperty(x => x.CreditorIBAN)
.KeyReference(x => x.Config, "ProfileName");
Map(x => x.ID, "ID").ReadOnly();
Map(x => x.CreationDate, "CreationDate").Default(null);
Map(x => x.ContractReference, "ContractReference");
Map(x => x.CreditorBIC, "CreditorBIC");
References<C_ContractType>(x => x.ContractType, "ContractType_ID");
References<C_Country>(x => x.CreditorCountry, "CreditorCountry");
Table("Creditor");
Cache.ReadWrite();
We can save on without any problem but when we try to update a field (no matter which one) with Session.SaveOrUpdate(entity);
nothing is done (no update) with no error message.
Did we missed something ? Thanks for your help !
-- EDIT --
I add Session.Flush()
after the update method and it's a little better as I can update any value except the ones that are in the key (CreditorName and CreditorIBAN). Any idea ?
Upvotes: 2
Views: 1090
Reputation: 123861
I. PERSISTING, executing sql write command
as discussed in the comments, the first thing we need to make that all happened is to extend the our code with a ISession.Flush()
(some cite)
...
Except when you explicity Flush(), there are absolutely no guarantees about when the Session executes the ADO.NET calls, only the order in which they are executed. ...
And as discussed here
How to change default FlushMode to Commit in C#?
We can assign the default flush mode during the session creation
var session = SessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
And be sure that it will be called once transaction is committed or call it explicitly anytime
we need to
Session.SaveOrUpdate(entity);
Session.Flush();
II. Key/Id change for already persisted, not transient entity
This is by design, by intention IMPOSSIBLE. Because the DB Key
, the C# runtime entity Id
is a data layer pointer to the instance. We should not work with these, we should not try to think about them
Our entities should just be managed with references:
var entity = ...;
entity.ContractType = someContractType;
entity.CreditorCountry = defaultCountry;
...
This way we assign db Keys, represented as Ids... on a Flush(), without mentioning them.
And that's also why we should not think about ability to change them.
The best we can do - is to not use Composite Key - and use
A surrogate key in a database is a unique identifier for either an entity in the modeled world or an object in the database. The surrogate key is not derived from application data, unlike a natural (or business) key which is derived from application data.
With SQL Server it is very easy to introduce new column with IDENTITY(1,1)... just use ALTER TABLE TheID INT NOT NULL IDENTITY(1,1)
... and its there
Re-map all your composite parts to properties (.Map()
or .References()
) and then you can change anything you want
I can understand that this is not desired answer, but I would strongly suggest at least to think about it. Simply,
Key should be generated only once. Then left unchanged for ever ... or deleted with its row/instance
Upvotes: 2
Reputation: 64628
You have to Flush or Commit the session before the changes are written to the database.
Also look at this:
Upvotes: 0