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
Related
I am working on a Spring project which uses PostgreSQL and Liquibase. I need to add a unique constraint to a specific column in a table. The table already has a lot of entries and some of them violate the new unique constraint.
Since the application is in production, dropping the table is not an option. I need to implement some sort of modification to the data in the column, so that duplicates get indexed (e.g. we have 2 entries with the value 'foo', after the operation these entries should look something like 'foo' and 'foo2').
So far I've only implemented the change which adds the unique constraint, but I have yet to implement this modification. Is there any functionality in either PostgreSQL or Liquibase which might address this issue?
You need to create an SQL UPDATE query (or queries) that will modify the database and implement the logic that updates duplicates and sets unique values to them.
Then use change type sql in liquibase to instruct liquibase to run that query.
I hope the question is not too generic.
I have a table Person that has a PK Identity column Id.
Via C#, I insert new entries for Person and the Id get set to 1,2,3 for the 3 persons added.
Also via C#, I perform all deletions of the persons with Id=1,2,3 so that there's no Person in the Table anymore.
Afterwards, I run some change scripts (I can't post them as they are too long) also on Table Person.
I don't do any RESEED.
Now the fun:
If I call SELECT IDENT_CURRENT('Person') it shows 3 instead of 4.
If I do an insert of Person again, I get a Person with the Id 3 added instead of Id 4.
Any idea why and how this can happen?
EDIT
I think I found the explanation of my question:
While performing DB Changes via SQL Server Management Studio, The Designer creates
a temp table Tmp_Person and moves the data from Person inside there. Afterwards he performs a rename of Tmp_Person to Person. Since this is a new table the Index starts again from the beginning.
An IDENTITY property doesn't guarentee uniqueness. That's what a PRIMARY KEY or UNIQUE INDEX is for. This is covered in the documentation in the remarks section, along with other intended behaviour. CREATE TABLE (Transact-SQL) IDENTITY (Property) - Remarks:
The identity property on a column does not guarantee the following:
Uniqueness of the value - Uniqueness must be enforced by using a PRIMARY KEY or UNIQUE constraint or UNIQUE index.
Consecutive values within a transaction - A transaction inserting multiple rows is not guaranteed to get consecutive values for the rows
because other concurrent inserts might occur on the table. If values
must be consecutive then the transaction should use an exclusive lock
on the table or use the SERIALIZABLE isolation level.
Consecutive values after server restart or other failures -SQL Server might cache identity values for performance reasons and some of
the assigned values can be lost during a database failure or server
restart. This can result in gaps in the identity value upon insert. If
gaps are not acceptable then the application should use its own
mechanism to generate key values. Using a sequence generator with the
NOCACHE option can limit the gaps to transactions that are never
committed.
Reuse of values - For a given identity property with specific seed/increment, the identity values are not reused by the engine. If a
particular insert statement fails or if the insert statement is rolled
back then the consumed identity values are lost and will not be
generated again. This can result in gaps when the subsequent identity
values are generated.
These restrictions are part of the design in order to improve
performance, and because they are acceptable in many common
situations. If you cannot use identity values because of these
restrictions, create a separate table holding a current value and
manage access to the table and number assignment with your
application.
Emphasis mine for this question.
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)
In a simple Data Base design, entity tables have IDs (mostly auto increment)
But there are some system e.g. vtiger CRM that use a master table to store all newly created IDS.
My question is:
What is the benefits of described approach.
What is the name of described approach, if any. I mean what do designers call this
method?
moodle is another example of this method too. An example in Moodle:
mdl_context has all IDs of other modules:
mdl_context - id - contextlevel - instanceid - path - depth
values - 115 - 50 - 17 - /1/84/90/115 - 4
instanceid is the ID of other entity and contextlevel shows the table, for example 50 is a code for course table.
Without having mdl_context, mdl_course had it's own ID, so why does `mdl_course exists?
You may simply think about this when your database doesn't support auto increment columns and you would have to implement auto incremental values yourself.
Or due to limitations of specific implementation of auto increment in a database, based on you business rules, you need to customize auto increment module.
for example
When gaps in the column values, are important to NOT Happens.
Consider the selling scenario in witch you need to have exact sequence of numbers for billing_ number column. Using an auto increment approach will cause some problems:
1- If any bill, would be rejected you would lose a number (Rollback scenario)
2- In case of DELETE operation on Billing table (if happens) you will lose a number(Delete scenario)
3- In some distributed(clustered) DB environments like Oracle RAC (having multiple RDBMS nodes) and using oracle sequences as auto increment strategy, we must use a CACHE interval to maintain integrity, so again some numbers will be lost.
In these cases you may use a metadata table like crm_entity holding last used value per table on it(or any other information if needed). locking the metadata table will be inevitable, so in heavy TPS, there will be performance issue.
SQL DBMSs typically provide a key generator feature that can be directly associated with a column in a table, variously known as Identity or auto-incrementing columns. These suffer certain disadvantages however. The syntax is often highly proprietary and awkward to work with and the key generator usually comes with inbuilt limitations, such as not permitting updates or inserts or only allowing one such column per table. Table-based generator functions normally only work on insert, which means the value can't be accessed and used until after the row has been inserted, and they are associated with one table only, making it impossible to generate key values that are shared and distributed between tables.
To overcome those and other limitations, table-independent key generators are often used instead. Some DBMSs (Oracle, SQL Server) support this directly with special Sequence-generator objects that are independent of tables but other DBMSs do not. So keeping a sequence-generating table separate from other tables is a useful general way to create sequences without relying on DBMS-specific features.
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.