[SOLVED] PK Autogenerated GUID and RefetchAfterSave

Posts   
 
    
DPSoft
User
Posts: 23
Joined: 24-Jun-2004
# Posted on: 13-Oct-2004 16:55:51   

I have a single table called customer with a PK field named CustomerID that is of type uniqueidentifier, Is RowGuid set to Yes, and a default value of (newid()). The following code seems to work fine, except the PK field contains all 0's after the save:

DataAccessAdapter da = new DataAccessAdapter();
CustomerEntity ce = new CustomerEntity();
ce.CustName = "AAAAA";
if (da.SaveEntity(ce) == false)
    MessageBox.Show("Save Failed");
da.CloseConnection();

With that code, a record is added to the database. I figured since ce.CustomerID was not receiving the newly generated GUID, I needed to set the RefetchAfterSave flag. I changed the code as follows:

DataAccessAdapter da = new DataAccessAdapter();
CustomerEntity ce = new CustomerEntity();
ce.CustName = "AAAAA";
if (da.SaveEntity(ce,true) == false)
    MessageBox.Show("Save Failed");
da.CloseConnection();

I now receive the following error:

"During a recursive save action an entity's save action failed. The entity which failed is enclosed."

For testing purposes, Customer is an independent table with no related tables. I'm pretty sure the error is related to the fact that since the PK doesn't have a value after the save, it cannot refetch the data from the DB.

Any ideas on how to get the newly generated GUID into CustomerEntity.CustomerID following a save?

Thanks.

swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 13-Oct-2004 17:02:35   

I had the same problem myself, and forgot it twice after that.

You have to generate the GUID PK yourself in your code, then save, like below:

    DataAccessAdapter da = new DataAccessAdapter();
    CustomerEntity ce = new CustomerEntity();
    ce.CustName = "AAAAA";
    ce.[YourPrimaryKeyFieldAsGuid] = Guid.NewGuid();
    if (da.SaveEntity(ce) == false)
        MessageBox.Show("Save Failed");
    da.CloseConnection();

Dang, what was the reason? Something about RefetchAfterSave occuring before triggers like newid() would execute? It's some internal SQL server thing. Frans explained it to me once...

What I'm sure of, is that if a PrimaryKey is an incrementing integer RefetchAfterSave will give you the PK, but with Guids (uniqueidentifier) you need to set it yourself prior to the save.

Like I said, I think I've stumbled here and forgotten this was true on two or three different projects. simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 13-Oct-2004 17:14:56   

newid() can't be used to generate GUIDs in a query, as there is no way to read the value generated back properly, or I have to do some mumbo jumbo with first generate it, then put it in a parameter and then execute the insert. (which will not work in your case either).

There is also no need to do it in the db as it doesn't matter where you generate the GUID, it will always be unique. So a GUID is not an autonumber or sequenced value, it's just like another type in the db, like varchar or what have you, you have to provide the value yourself, indeed using Guid.NewGuid. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
DPSoft
User
Posts: 23
Joined: 24-Jun-2004
# Posted on: 13-Oct-2004 17:57:44   

In researching this a bit more after help from you guys, I understand the problem to be a limitation in SQL Server. Select @@Identity does not work for GUID's. It sounds like the best route is to simply generate the GUID in code, which I assume can be done in a generic manner as part of the save routine (if PK is blank, create and assign GUID before persisting, otherwise use the existing GUID).

Frans, I might suggest revising the documentation to reflect this limitation (albeit a SQL Server limitation):

"The code is aware of sequences / identity columns and will automatically set the value for an identity / sequence column after the entity is physically saved inside SaveEntity(). The new value for sequenced columns is available to you after SaveEntity(), even though you haven't specified that the entity has to be refetched. This can be helpful if you want to refetch the entity later. Because the entity saved is new (customer.IsNew is true), SaveEntity() will use an INSERT query. After a successful save, the IsNew flag is set to false and the State property of the Fields object of the saved entity is set to EntityState.Fetched (if the entity is also refetched) or EntityState.OutOfSync. "

A quick side note to indicate this does not work for SQL Server using autogenerated GUID's might save people a few gray hairs!

Thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 13-Oct-2004 18:22:47   

Hmm, that is if you consider fields with autogenerated guids sequenced fields wink . I mean: you can also call a function as a default value for a pk field or worse: let a trigger do the pk value creation simple_smile .

I'll add a note to the docs.

Frans Bouma | Lead developer LLBLGen Pro
DPSoft
User
Posts: 23
Joined: 24-Jun-2004
# Posted on: 13-Oct-2004 18:42:08   

Otis wrote:

Hmm, that is if you consider fields with autogenerated guids sequenced fields wink . I mean: you can also call a function as a default value for a pk field or worse: let a trigger do the pk value creation simple_smile .

I'll add a note to the docs.

LOL. You are right. I guess I wouldn't consider an autogenerated GUID a sequenced field! That was the one place in the docs I found that made mention of entities pulling back the newly generated PK automatically, so thought it might be appropriate to put a small note in there. Maybe it would be something good to add to the Best practices section instead. There are bound to be others that run into this SQL Server limitation in the future, and incorrectly think it is an LLBLGen problem.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 13-Oct-2004 20:29:54   

I've added a note to the section where the PK sequencing is mentioned and I've explained that triggers, default constraints and newid constructs will not make the value be read back simple_smile It was indeed somewhat confusing. For example on Firebird, it's common practise to use a trigger to insert a sequence value, which will cause wrong results, as the PK value is always 1 higher than the value initially inserted due to the trigger (so the entity will never be read back simple_smile )

Frans Bouma | Lead developer LLBLGen Pro
swallace
User
Posts: 648
Joined: 18-Aug-2003
# Posted on: 13-Oct-2004 21:22:59   

I knew there was a reason.

I wonder how many things there are in my life where I do it but can't remember why? confused

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39888
Joined: 17-Aug-2003
# Posted on: 13-Oct-2004 21:32:45   

swallace wrote:

I knew there was a reason.

I wonder how many things there are in my life where I do it but can't remember why? confused

hehe, as long as it doesn't bit you in the face, don't worry wink

Frans Bouma | Lead developer LLBLGen Pro