I want to use the EF (4.2) in the following scenario:
- There exists a database already (so I chose the database-first approach) and it is a SQL Anywhere DB.
- I want to use persistence-ignorant business objects, so I use the
DbContext
Template to generatePOCO
classes from the EDM. - There is one simple inheritance hierarchy among my entities: an abstract base entity and two concrete derived entities.
- In the database there is one table for each type of the inheritance hierarchy (Table-Per-Type Strategy).
- Each of these three tables has a primary key column (
Id
, type:integer
), and the association of a concrete entity to the base entity is done by having the sameId
in both tables (that means that the primary key (Id
) of the concrete type tables is at the same time a foreign key to the base table; a pretty common approach I think).
I had to define the Inheritance manually in the designer, since the EDM assistant does not automatically recognize, that is want to have an inheritance association between the described entities.
Until this point there wasn't any bigger problem. Now to the issue at hand:
There is a restriction for the database I use: Primarykey
values have to be generated by the database, using a database function.
I want to call this function in a before-insert-trigger
defined on the base-table
.
To let the entity framework know that a value is generated by the database, I set the StoreGeneratedPattern
property of the Id
Property of the base-entity
to Identity
(As I understood, this is the way to tell EF to get the generated value after inserting a new instance of an entity).
When I create a new instance of a derived entity, add it to the corresponding DbSet
of the DbContext
and call SaveChanges
on the context, a DbUpdateException
is thrown, stating that a foreignkey
constraint is violated.
By checking the request-log of the DB, I see that the base entity got inserted in the base table, but on inserting the row in the derived table, the above mentioned error occurs, because it obviously doesn't use the newly generated Id
of the new entry in the base table.
Since I don't think there is much I can do on a database level against that, the question is, if the EDM or DbContext can be configured (or modified) to insert the base row first, then take the generated Id
and use it for insertion of the derived row.
I know there are several way to avoid this situation (not using inheritance, using a stored procedure to insert a new derived entity, calling the id-generating db-function before inserting and set the Id
property myself on the entity), but at the moment the above-described behavior would be the most preferable, so I want to make sure not to overlook something before deciding for any "plan B".
Any suggestions on this topic are much appreciated, Thanks in advance.
Here is the code of the trigger:
ALTER TRIGGER "TRG_GENERATE_ID" before insert order 1 on
BASE_TABLE
referencing new as NewEntry
for each row
begin
declare NewID integer;
set NewID = F_GET_NEW_ID('BASE_TABLE', NewEntry.SOME_OTHER_ID);
set NewEntry.ID = NewID
end
The function "F_GET_NEW_ID" is called in the trigger to generate the new ID for a new entry in the base table. It has two parameters: "Tablename" -> The name of the table for which a new ID should be generated, and a second parameter that takes the value of a standardcolumn in all tables of the database (it is required to generate the new ID).