2

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 ?

SeyoS
  • 661
  • 5
  • 22
  • Very important thing here is: "Session.SaveOrUpdate(entity)" does **not** persist anything. It just changes data in the session (if detached previously)... be sure you've called **`Session.Flush()`** – Radim Köhler Jun 17 '15 at 10:07
  • @RadimKöhler : Thanks. As you might have seen, I add this but it's just a little better. Any other idea ? – SeyoS Jun 18 '15 at 07:49
  • Seyos, you most likely won't like my answer, but I think it is the best advice I can share.. hope it helps a bit... – Radim Köhler Jun 18 '15 at 08:13

2 Answers2

2

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()

9.6. 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

Surrogate Key

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

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • *Sig* I knew it would come to something like this... Argh ! – SeyoS Jun 18 '15 at 08:21
  • Wish to have a better one.. Enjoy mighty NHibernate, sir! It is amazing tool ;) – Radim Köhler Jun 18 '15 at 08:22
  • 1
    Honestly, i don't like it. It is helpful in most case but just because of 5% of those case, I prefer using something else. It's just that this project is an old one that I use it. – SeyoS Jun 18 '15 at 08:24
0

You have to Flush or Commit the session before the changes are written to the database.

Also look at this:

Community
  • 1
  • 1
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • Thanks. I did this and it's a little better as I can update any value except the ones that are the key (CreditorName and CreditorIBAN). Any idea ? – SeyoS Jun 17 '15 at 11:44