My application supports SQL Server and Compact edition. I use EntityFramework as the data access layer. To allow the users to go from Compact to SQL Server and back to Compact, I have a method to copy the data from one database to the other. This works fine from Compact to SQL Server, but when I use the same code to copy from SQL Server to Compact I get exceptions telling me that I cannot add a row with duplicate Id after an object was added to the EF data context and calling context.SaveChanges().
Here is how I copy the tables:
I let EF create the destination database
Open a SqlConnection(SqlCeConnection to source DB and destination DB
Foreach table I:
On the destination database SET IDENTITY_INSERT [Tablename] ON
Copy the table row by row using Sql inserts, including the ID's
On the destination database SET IDENTITY_INSERT [Tablename] OFF
So after I copy the database from SQL Server to Compact and using it with Entity Framework I get the above mentioned exception. So it looks like SET IDENTITY_INSERT ON works (because the data gets into the Compact database) but SET IDENTITY_INSERT OFF does not work on SQL Compact.
Does anyone has similar experiences and a solution for me?
If you are getting an error that it is trying to add a duplicate key, then the issue you are having doesn't have anything to do with the IDENTITY_INSERT setting. The identity insert only persists during your session.
What is probably happening is that you have inserted key values that are above the current identity seed values. You can reseed your table's identity seed with this command in SQL Server:
DBCC CHECKIDENT (MyTable, reseed)
You can execute this in Entity Framwork with:
context.Database.ExecuteSqlCommand("DBCC CHECKIDENT(MyTable, reseed)")
This will reset the seed to start numbering after the last value used in the table. Run this statement after populating every destination table.
Ok, ErikEJ tip brought me to the right direction. The final resolution was to
a) get the current max Id
SELECT MAX(Id) FROM TABLENAME
b) Reseeding but with MAX + 1
ALTER TABLE [TABLENAME] ALTER COLUMN [Id] IDENTITY (<MAX + 1>,1)
Related
I am dealing with this problem: I would like to have autogenerated identity in my table which is of type int
But, I would like to be able to explicitly set the identity. Now the real challenge is that this stuff is going through Entity Framework. I have my database with a IDENTITY(1,1) column, and IDENTITY_INSERT set to ON.
And whenever the Id is 0 (not specified) in newly created object, it inserts the very same 0. Any help appreciated, except offers to reconsider architecture (I will do that in any other case if this attempt fails).
And all this must work either on SQL CE, and SQL Server.
If you tell EF the primary key is database generated then it will not pass the id to the insert sql. You need to pass the ID so go with DatabaseGenerated.None.
But you want it to be an IDENTITY, so make it one in a migration script. You could change the CREATETABLE statement, adding identity: true to the column specification, or you can modify the table by running sql using the Sql() method
Now you need to modify the actual sql run during insert. The only way to do that is configure your model to use stored procedures then modify the sql generated in the Up migration for the insert procedures:
CREATE PROCEDURE [dbo].[My_Insert]
#Id int,
--ETC
AS
BEGIN
IF(Id > 0) SET IDENTITY_INSERT ON
INSERT --ETC
IF(Id > 0) THEN BEGIN
SET IDENTITY_INSERT OFF
SELECT Id
ELSE
SELECT SCOPE_IDENTITY() AS Id
END
END
I have to do data migration.
For that I have to disable the identity for a column & after adding data there is need to enable that identity again for the same column in SQL Server 2008.
Can someone explain how to do that or is there any other way to do the same task?
If you're doing your migration using normal INSERT statements, then you can use IDENTITY_INSERT*:
SET IDENTITY_INSERT abc ON
INSERT INTO abc (/* Columns */) VALUES
(/* Values */)
SET IDENTITY_INSERT abc OFF
If you're using BULK INSERT, then you'd want the KEEPIDENTITY option.
If you're using the SSIS OLE DB Destination then you'd want to use the Keep Identity option.
If you're using the SQL Server Import and Export Wizard, then when you've selected appropriate sheets/tables on the Select Source Tables and Views page of the wizard, select Edit Mappings... and tick the Enable identity insert option.
*Many people find this option confusingly named, because they assume that they're telling the system what to do - "Please insert identity values" - instead, the sense is "I'm going to insert identity values". That's why you turn it on before the inserts and off afterwards, rather than vice versa.
Use SET IDENTITY_INSERT (http://msdn.microsoft.com/en-us/library/ms188059.aspx).
SET IDENTITY_INSERT TableName ON;
-- Insert Data.
SET IDENTITY_INSERT TableName OFF;
I have an application that uses a SQL Server database with several instances of the database...test, prod, etc... I am making some application changes and one of the changes involves changing a column from a nvarchar(max) to a nvarchar(200) so that I can add a unique constraint on it. SQL Server tells me that this requires dropping the table and recreating it.
I want to put together a script that will do the table drop, recreate it with the new schema, and then reinsert the data that was there previously all in one go, if possible, just to keep things simple for use when I migrate this change to production.
There is probably a good SQL Server way to do this but I'm just not aware of it. If I was using Mysql I would mysqldump the table and its contents, and use that as my script for applying that change to production. I can't find any export functionality in SQL server that will give me a text file consisting of inserts for all data in a table.
Use SQL Server's Generate Scripts command
right click on the database; Tasks -> Generate Scripts
select your tables, click Next
click the Advanced button
find Types of data to script - choose Schema and Data.
you can then choose to save to file, or put in new query window.
results in INSERT statements for all table data selected in bullet 2.
No need to script
here are two ways
1 use alter table ....alter column.....
example..you have to do 1 column at a time
create table Test(SomeColumn nvarchar(max))
go
alter table Test alter column SomeColumn nvarchar(200)
go
2 dump into a new table while converting the column
select <columns except for the columns you want to change>,
convert(nvarchar(200),YourColumn) as YourColumn
into SomeNewTable
from OldTable
drop old table
rename this table to the same table as the old table
EXEC sp_rename 'SomeNewTable', 'OldTable';
Now add your index
I am using
exec sp_generate_inserts 'TABLENAME'
to copy all the records of one table from our test server to live server.
Do we have to create the table first before using this command?????
I tried to give this command and it gives me an error - Invalid Object name.
I tried to create the table first and then to give this command. But in that case I have an identity column in the table and it gives an error..... Cannot insert identity value .
I know that the identity insert is set to off. Do I have to turn it on and try....How can turn it on.....And also could you please let me know if we have an alternative way of doing it.
Thanks
YES of course you have to create the table first before inserting data into it....
And if you want to insert specific values into an IDENTITY column, you can use
SET IDENTITY_INSERT (your table name) ON
-- do your INSERTs here
SET IDENTITY_INSERT (your table name) OFF
I've just moved a database from a SQL 2000 instance to a SQL 2008 instance and have encountered an odd problem which appears to be related to IDENTITY columns and stored procedures.
I have a number of stored procedures in the database along the lines of this
create procedure usp_add_something #somethingId int, #somethingName nvarchar(100)
with encryption
as
-- If there's an ID then update the record
if #somethingId <> -1 begin
UPDATE something SET somethingName = #somethingName
end else begin
-- Add a new record
INSERT INTO something ( somethingName ) VALUES ( #somethingName )
end
go
These are all created as ENCRYPTED stored procedures. The id column (e.g. somethingId in this example) is an IDENTITY(1,1) with a PRIMARY KEY on it, and there are lots of rows in these tables.
Upon restoring onto the SQL 2008 instance a lot of my database seems to be working fine, but calls like
exec usp_add_something #somethingId = -1, #somethingName = 'A Name'
result in an error like this:
Violation of PRIMARY KEY constraint 'Something_PK'. Cannot insert duplicate key in object 'dbo.something'.
It seems that something is messed up that either causes SQL Server to not allocate the next IDENTITY correctly...or something like that. This is very odd!
I'm able to INSERT into the table directly without specifying the id column and it allocates an id just fine for the identity column.
There are no records with somethingId = -1 ... not that that should make any difference.
If I drop and recreate the procedure the problem goes away. But I have lots of these procedures so don't really want to do that in case I miss some or there is a customized procedure in the database that I overwrite.
Does anyone know of any known issues to do with this? (and a solution ideally!)
Is there a different way I should be moving my sql 2000 database to the sql 2008 instance? e.g. is it likely that Detach and Attach would behave differently?
I've tried recompiling the procedure using sp_recompile 'usp_add_something' but that didn't solve the problem, so I can't simply call that on all procedures.
thanks for any help
R
(cross-posted here)
If the problem is an improperly set identity seed, you can reset a table this way:
DBCC CHECKIDENT (TableName, RESEED, 0);
DBCC CHECKIDENT (TableName, RESEED);
This will automatically find the highest value in the table and set the seed appropriately so you don't have to do a SELECT Max() query. Now fixing the table can be done in automation, without dynamic SQL or manual script writing.
But you said you can insert to the table directly without a problem, so it's probably not the issue. But I wanted to post to set the record straight about the easy way to reset the identity seed.
Note: if your table's increment is negative, or you in the past reset the seed to use up all negative numbers starting at the lowest after consuming all the positive numbers, all bets are off. Especially in the latter case (having a positive increment, but you are using identity values lower than others already in the table), then you do not want to run DBCC CHECKIDENT without specifying NORESEED ever. Because just DBCC CHECKIDENT (TableName); will screw up your identity value. You must use DBCC CHECKIDENT (TableName, NORESEED). Fun times will ensue if you forget this. :)
First, check the maximum ID from your table:
select max(id_column) from YourTable
Then, check the current identity seed:
select ident_seed('YourTable')
If the current seed is lower than the maximum, reseed the table with dbcc checkident:
DBCC CHECKIDENT (YourTable, RESEED, 42)
Where 42 is the current maximum.
Demonstration code for how this can go wrong:
create table YourTable (id int identity primary key, name varchar(25))
DBCC CHECKIDENT (YourTable, RESEED, 42)
insert into YourTable (name) values ('Zaphod Beeblebrox')
DBCC CHECKIDENT (YourTable, RESEED, 41)
insert into YourTable (name) values ('Ford Prefect') --> Violation of PRIMARY KEY
I tried and was unable to replicate this on another server.
However, on my Live servers I dropped the problem database from sql 2008 and recreated it using a detach and reattach and this worked fine, without these PRIMARY KEY VIOLATION errors.
Since I wanted to keep the original database live, in fact my exact steps were:
back up sourceDb and restore as sourceDbCopy on the same instance
take sourceDbCopy offline
move the sourceDbCopy files to the new server
attach the database
rename the database to the original name
If recreating the procedures helps, here's an easy way to generate a recreation script:
Right click database -> Tasks -> Generate scripts
On page 2 ("Choose Objects") select the stored procedures
On page 3 ("set scripting options") choose Advanced -> Script DROP and CREATE and set it to Script DROP and CREATE.
Save the script somewhere and run it