3

This question is related to another question i asked here ( Entity Framework 4.2 - How to realize TPT-Inheritance with Database-generated Primarykey Value? ) and should simply clarify, if my assumptions, regarding the problem stated in the topic, are right or not.

The Problem (in detail):

  • I want to use EF (4.1) to access a database, that already exists
  • the database has some restrictions regarding the generation of primary key values for its tables (there is a UDF that takes a tablename and returns the next available ID)
  • To make things as easy as possible for myself, my first approach was to define database triggers (before insert) that call the ID-generating UDF to set the new ID on inserting a new datarow
  • Then i set the StoreGeneratedPattern properties of the corresponding entities in the csdl of my EDM to "Identity", so that the newly generated IDs would be set in the entity objects after saving them to the DB

The Result of this was:

When I created a new entity object, added it to the DbContext and called SaveChanges on it, the corresponding datarow was inserted in the database, but the entity was not updated with the new database-generated ID. I realized this when i tried to save more at once, that have associations to each other (parent-child), because the foreignkey properties of the child entities could not be set correctly, since the new ID of the parent was not known to the DbContext.

This is the reason I asked the above mentioned question concerning TPT inheritance.

After several days of research and trying everything that came to my mind to solve this problem, i think i realized, that this simply cannot work. Although the documentation of the StoreGeneratedPattern enum at MSDN and several explanations in blogs suggests, that StoreGeneratedPattern.Identity should be set to retrieve the generated value, when the DB generates a value on inserting a new row, this is not true for primary keys in conjunction with database triggers.

After thinking about that a long time, that seems perfectly logical to me, since the EF needs some criterium to retrieve database-generated values, and i think that would be in most cases the identity of an entity. For databasecolumns that are set to autoincrement (or identity-column, ...) that might be no problem, because the DBMS provides some functionality to retrieve the last inserted identity-value (e.g. @@identity in MSSQL). But when using a trigger to generate a new identity-value, the EF obviously doesnt know how to query the newly inserted row (and i cant imagine any good db-independent way to do this either).

So my actual question is: are the assumptions above correct or am I overlooking something important here?

Thanks in advance for any clarification/inspiration on this.

Edit (followup question):

After reading the answer from Ladislav another question arises:

If I set StoreGeneratedPattern in CSDL, do I have to set it to the same value in SSDL (and vice versa)? The patch for the edm designer implies that this is the case, because it automatically synchronizes the StoreGeneratedPattern in SSDL when you change it in CSDL (through the designer).

Community
  • 1
  • 1

2 Answers2

1

The StoreGeneratedPattern.Identity should work. If you set it in EF Designer make sure that it was correctly configured in both SSDL and CSDL parts of EDMX file (open it as XML to check it). There was a bug in EF designer which caused correct setting only in CSDL so SQL part didn't know that new ID must be selected from the database after insert. This bug was in some rare cases solved by installing VS 2010 SP1 and it should be definitely solved by special patch.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I have the patch installed, also I tried various combinations of StoreGeneratedPattern values in SSDL and CSDL. None of them works for me. In a test example with SQLEXPRESS DB the following SQL statement is issued to query the new ID: `select [id] from [dbo].[ParentEntities] where @@ROWCOUNT > 0 and [id] = scope_identity()`. The scope_identity function works only for identity columns, but i don't have a identity column, since i generate my IDs in the trigger. – Hanns Echtleder Dec 28 '11 at 09:19
  • Yes both values in CSDL and SSDL must be the same. As a workaround you can create custom stored procedures for inserting entity (and probably also for updating and deleting) and in stored procedure call your UDF and return correct ID. – Ladislav Mrnka Dec 28 '11 at 10:25
  • Thanks for your answer. Can you also make a statement, whether `StoreGeneratedPattern.Identity` in conjunction with primarykey columns only works with identity-/autoincrement-columns (I suppose the behavior for querying the generated ID in this case depends on the DBMS specific EF provider) and **NOT** with database triggers? – Hanns Echtleder Dec 28 '11 at 12:18
0

I had the same problem: one of the column was set with trigger.

But it appeared that I did have troubles with VS edmx designer ('Identity' hadn't been set), and it helped fix it manually (one model had correct value, but other didn't).

Then we got "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries". That was easily fixed following instuctions here

If I set StoreGeneratedPattern in CSDL, do I have to set it to the same value in SSDL (and vice versa)?

Yes, it seems to not work without changes to both CSDL and SSDL

Community
  • 1
  • 1