Autoincrement in Entity Framework 5 without identity column in database - sql-server

I have not been able to find any appropriate solution for my problem, so here's my question for you:
In Entity Framework (5.0), how can I setup an ID-column (PK) to be autocremented when no identity column is defined in the actual database (SQL Server 2005)?
I have seen the StoreGeneratedPattern, but not sure how this would work without identity in the db. The manual approach would be to manually populate the POCO with MAX(id)+1, but that feels like a hack and I'm worried that it will introduce problems in a multi-threaded environment where multiple requests may insert records to my table at the "same" time.
Note that I do not have the possibility to alter the table schema in the database.
What's the best way to solve this?

If one instance of your application is the only thing inserting rows into this table, then the MAX(Id) + 1 hack is probably good enough. Otherwise, you'll need to alter the database schema to generate these values on insert -- either by using IDENTITY or by re-inventing the wheel using triggers, sprocs, etc.
Whatever your solution, it should guarantee that a duplicate key will never be generated -- even if a transaction happens to rollback one or more inserts.
If nothing else inserts into the table, you should be able to alter Id to an identity column without breaking compatibility.
FYI: Entity Framework's StoreGeneratedPattern (or DatabaseGeneratedOption) only specifies how values are handled on insert and update. Using Identity tells EF that the value is expected to be generated by the database on insert. Computed means it's generated on both insert and update.

Related

Control Behavior of Constraints During SQL Bulk Insert?

I am curious if there is a way to control how the database responds to foreign and primary key constraints while using the bulk insert command. Specifically, I am inserting data into an employees table (with primary key empID), that is linked to data in other tables (children, spouse, and so on) by that key (empID). Given the logic and purpose behind this application, if, during bulk insert, a duplicate primary key is found, I would like to do the following:
Delete (or update) the 'employee' row that already exists in the database.
Delete all data from other tables associated with that employee (that is children, beneficiaries, and so on).
Insert the new employee data.
If I was inserting data the usual way, that is without bulk insert, I think the task would be quite simple. However, as am using it, I must admit, I am not quite certain how to approach this.
I am certainly not expecting anybody to write my code for me, but I am not quite sure if it is even possible, how to begin, or what the best approach might be. A stored procedure perhaps, or changes to schema?
Thanks so much for any guidance.
The usual solution to this kind of problem is to load the data into a Staging table, perhaps in it's own Schema or even Database. You would then load the actual table from this staging table, allowing you to perform whatever logic is required in an un-restricted manner. This has the added benefit of letting you log/audit/check the logic you are using while loading the 'real' table.

Changing columns to identity (SQL Server)

My company has an application with a bunch of database tables that used to use a sequence table to determine the next value to use. Recently, we switched this to using an identity property. The problem is that in order to upgrade a client to the latest version of the software, we have to change about 150 tables to identity. To do this manually, you can right click on a table, choose design, change (Is Identity) to "Yes" and then save the table. From what I understand, in the background, SQL Server exports this to a temporary table, drops the table and then copies everything back into the new table. Clients may have their own unique indexes and possibly other things specific to the client, so making a generic script isn't really an option.
It would be really awesome if there was a stored procedure for scripting this task rather than doing it in the GUI (which takes FOREVER). We made a macro that can go through and do this, but even then, it takes a long time to run and is error prone. Something like: exec sp_change_to_identity 'table_name', 'column name'
Does something like this exist? If not, how would you handle this situation?
Update: This is SQL Server 2008 R2.
This is what SSMS seems to do:
Obtain and Drop all the foreign keys pointing to the original table.
Obtain the Indexes, Triggers, Foreign Keys and Statistics of the original table.
Create a temp_table with the same schema as the original table, with the Identity field.
Insert into temp_table all the rows from the original table (Identity_Insert On).
Drop the original table (this will drop its indexes, triggers, foreign keys and statistics)
Rename temp_table to the original table name
Recreate the foreign keys obtained in (1)
Recreate the objects obtained in (2)

Entity Framework Identity Increment Configuration

Is it possible to configure an Entity Framework model so that, when creating a database from the model, generated identity columns have an identity increment other than 1? For example, I might have an identity column where I want the sequence of ids to go: 1, 11, 21, 31, ... (counting by 10 instead of 1).
I am not too concerned about the identity seed since I can easily re-seed a table with a sql statement after EF generates the db schema. However, it appears that if I'd like to change an identity increment, then I must re-create the table (at least in Microsoft Sql Server). This could be somewhat complex to do automatically because of foreign key relationships.
So is there any way to configure identity columns in EF? If not, I'd also be OK with inspecting and modifying the schema creation scripts before they're executed against the db if that's possible.
Update with some additional details:
I have already overridden the Seed method exposed by DropCreateDatabaseIfModelChanges (an included implementer of IDatabaseInitializer). Here I run a few custom initialization routines after the schema is created by EF. I was thinking that I could add another one to modify each identity column specification after creation. However, as noted above, to change the identity increment I have to re-create each table (and its foreign keys). In the absence of an easy way to change an identity column increment after it's created, I'd like to configure the identity columns before they're created so EF creates them with an increment other than 1, or alternatively modify the table creation scripts produced by EF before they're executed.
You cannot change the seed - EF doesn't allow that. Also changing the seed on the existing table means dropping the column and creating it again. So the answer to this part is no.
Creating scripts "is possible" but you will lost a lot of features EF is doing for you. You will probably lose:
Database creation - you will only get script to create tables
Database consistency check (EdmMetadata support)
Check this article about creating initializer for existing database which retrievs

Integration services and identity columns

I am a bit of an SSIS newbie and while the whole system seems straightforward, I don't conceptually understand the process I need to go through in this scenario:
Need to map Invoice and InvoiceLine tables from a source database to two equivalent tables in a destination database - with different identity values.
For each invoice inserted across, I need to get the identity it was assigned and then insert all its lines referencing that new identity
There is a surrogate key on the invoices (the invoice number), however these might also clash with invoice numbers in the target system, hence they would also have to be renumbered.
This must be a common scenario in integration - is there a common solution?
Chris KL - you are correct that this is harder than one would expect. I have three methods for this, which work in different situations:
IF the data you are loading is small (hundreds or thousands but not hundreds OF thousands) then you can do this: use an OLEDB command that performs one insert for each parent row and returns the identity value back; then downstream from that join the output from that to the child rows, and insert them. Advantage: intuitive. Disadvantage: scales badly. This method is documented on the web and should Google for you.
If we are talking about a bigger system where you need bulk loading, then there are two other flavors:
a. If you have exclusive access to the table during the load (really exclusive, enforced in some way) then you can grab the max existing ID from the table, use an SSIS script task to number the rows starting above that max id, then Set Identity Insert On, stuff them in, and Set Identity Insert Off. You then have those script-generated keys in SSIS to assign to the child rows. Advantage: fast and simple, one trip to the DB. Disadvantage: possible errors if some other process inserts into your table at the same time. Brittle.
b. If you don't have exclusive access, then the only way I know of is with a round trip to the DB, thus: Insert all parent rows but keep track of a key for them that is not the identity column (a business key, for example). In a second dataflow, process the child records by using a Lookup transform that uses the business key to fetch the parent ID. Make sure the lookup is tuned appropriately vs. caching, and that thee business key is indexed.
OK, this is a good news / bad news situation I'm afraid. First the good news and a bit of background which you may know but I'll put it down in case you don't.
You generally can't insert anything into IDENTITY columns. Of course, like everything else in life there are times when you need to and that can be done with the IDENTITY_INSERT option.
SET IDENTITY_INSERT MyTable ON
INSERT INTO MyTable (
MyIdCol,
Etc…
)
SELECT SourceIdCol,
Etc…
FROM MySourceTable
SET IDENTITY_INSERT MyTable OFF
Now, you say that you have surrogate keys in the target but then you say that they may clash. So I'm a little confused… Are you using the keys from the source (e.g. IDENTITY columns) or are you generating new keys in the target? I would strongly advise against trying to merge the keyspaces in a single key column. If you need to retain the keys then I would suggest a multi-field key using something like SourceSystemId to keep them unique.
Finally the bad news: SSIS doesn't provide a simple means of using the IDENTITY_INSERT option. The only way I've been able to do it is by turning it on in a SQL task that executes before the insert task. You should be able to pass the table name into the script as a variable. Make sure to include another SQL task afterwards to turn it off because you can only use on one table at a time.

MS-SQL Filling in Identity column values

I'm building an ASP.Net/MVC application using SQL 2008 Developer edition and a DB in Sql2005 compatibility mode. Using Entity Framework as DAL.
My problem is that I have a table where I'm using the integer identity column in a like an Invoice Number, that is, it always has to be unique and never reused. So using the GUID column type won't work without a substantial effort.
What I'm seeing is that the DB is filling in the gaps in the identity column. This will cause me long term problems. Is there a setting to disable this "filling in"
That sounds like something outside SQL server; SQL server does not "go back" and re-use gaps in identities unless the table's been reseeded, but even then it will blindly increment one-by-one and probably return a lot of duplicate key errors as it hits rows with existing values.
Are you sure the column is an identity? Is there anything else that might be re-assigning keys and/or turning on identity insert when creating rows?
SQL Server does not fill in the gaps of an identity field by default it will just keep going up in numbers as you insert rows.
It is possible to reset the identity back to 1 and therefore you may then see what you are describing.
Can I suggest you post some code / db structure that shows your problem and search for any code you may have that my perform an identity reseed.
Unless I am not understanding your issue correctly. If you create a primary key on your identity column, or a unique constraint, you can avoid the issue of duplicate values.
For example:
create table TableName
(
InvoiceID int identity(1,1) not null primary key
)

Resources