How to switch turn DatabaseGeneratedOption.Identity on/off at runtime - sql-server

I have a DB that created by EF6 Code First. Some tables have an identity column. I need to insert some records to these tables with OLD Id values.
I tried the solution that appeared in this link How to switch between DatabaseGeneratedOption.Identity... that demonstrates how to switch between computed and none options, but not on an identity column.
When I tried to do it, I got this error message: "Cannot insert explicit value for identity column in table 'Links' when IDENTITY_INSERT is set to OFF."
Is there any way to solve this?

The problem you are facing is that EF sends explicit ID values to the DBMS, but it expects none while IDENTITY_INSERT is set to off.
You have to do the following additionally:
context.Database.ExecuteSqlCommand("SET IDENTITY_INSERT Links ON");
This tells your DBMS to also accept explicit values.
For this to work, you will have to wrap this command and (at least) SaveChanges() into one transaction.

Related

Auto update time in SQL Server

I would like to have two columns in my table to store the add-time and update-time. As the name suggests, the add-time is the time when a row was first added; the update-time is the last time a row was updated. I can implement first by defaulting value to GETDATE(). As for the second, #Jeremy suggested using triggers here:
On Update: Auto Update Date/Time Field
Is there any easier way?
If I implement a trigger, does that mean two UPDATE statements (or one INSERT and one UPDATE in case the row is just created) have to be executed?
Thanks.
EDIT: For the second part of the question, this is the trigger I have in my database:
CREATE TRIGGER [dbo].[TR_AddUpdateTime]
ON [dbo].[AddUpdateTime]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
UPDATE r
SET UpdateTime = GETDATE()
FROM AddUpdateTime r
JOIN inserted i
ON i.Id = r.Id
END
Does this mean that an additional update statement will be executed whenever I make an update to AddUpdateTime table, or MSSQL is smart enough to recognise that I am updating the same record and save both changes at the same time?
Other ways:
Use a stored procedure to wrap the updates
You can do UPDATE MyTable SET ..., UpdatedWhen = DEFAULT...
You need an UPDATE trigger that itself has one more UPDATE. Using a default on the table means you don't need a trigger for INSERT
You could make sure all inserts and updates go through a stored procedure that inserts the time.
No, the insert trigger will modify the values so that it's only one statement.
Edit: For entity framework could you implement the OnSavingChanges event to insert the update-time field (see here)? This is moving the responsibility from the DB to the Code which you may or may not be comfortable with.
In entity framework, you can use the partial class to extend the business logic. In this case, you can use OnPropertyChanged to set the update-time to DateTime.Now. You can use this article on MSDN as a guidance.
1) "Auto update" and "triggers" doesn't really sound like the way to go.
2) SQL Server has a (relatively new) "merge" statement. But that doesn't really sound like what you're looking for, either.
3) Instead:
a) If primary key doesn't exist (if "new"), then INSERT. In this case, first time = last time = GETDATE().
b) Otherwise, if the primary key already exists, then UPDATE. Your update will update only the "last time" column (along with the rest of the fields you need to update for this record.
4) Perhaps you can wrap this logic in a stored procedure?
5) Again - the key is to update BOTH "first time" and "last time*, the FIRST TIME, and then update ONLY "last time" all SUBSEQUENT times.
They might be an easier way but using triggers will be more effective and will guarantee no mater how records inseted or updated (from .net code or direct table inserts/updates), those two fields are populated
To Gurantee that only one trigger get fired each time, combine insert and update trigger
CREATE TRIGGER <trigger name> ON TableA for INSERT,UPDATE
And do conditional checking to distinguish between two actions
IF UPDATE

Cannot insert duplicate record in a table

I am trying to execute stored proc through SSIS and it gives me following error:
[Execute SQL Task] Error: Executing
the query "Exec sp1 ?" failed with
the following error: "Procedure: sp1
Line: 66 Message: Cannot insert
duplicate key row in object
'table.sq1' with unique index
'UIX_sp1_Key'.". Possible failure
reasons: Problems with the query,
"ResultSet" property not set
correctly, parameters not set
correctly, or connection not
established correctly.
Actually the stored Proc sp1 is truncating & reloading a data into a table.
I am not able to figure out where exactly its trying to insert duplicate record.
Thanks in advance.
Your data must have duplicate values across the key column(s). You could remove the primary key temporarily (or create another table with the same structure but without the definition of the primary key, but that would mean changing the stored procedure), then load the data into the table. Then use this SQL statement:
select keycol1 {,keycol2 {,keycol3} ...}, count(*)
from tablename
group by keycol1 {,keycol2 {,keycol3} ...}
having count(*) > 1
That will show you the data values that are duplicates across the key column(s).
If you are truncating the table before load, then you must have duplicate data in the source.
Examine this to see what there is. use Excel or Access or some such if needed to assist. Or drop the unique constraint then query the staging table with an aggregate query.

Can't set auto-increment via SQL Server Express Management Studio?

I just tried inserting value in to a database and that work. Now I insert again and I get an error for identical primary key.
I can't find any option to alter it to be auto-increment.
I'm updating the table via Linq-To-Sql.
User u = new User(email.Text, HttpContext.Current.Request.UserHostAddress,
CalculateMD5Hash(password.Text));
db.Users.InsertOnSubmit(g);
db.SubmitChanges();
I didn't fill in the user_id and it worked fine the first time. It became zero.
Trying to add a second user, it wants to make the ID 0 again.
I could query the database and ask for the highest ID, but that's going to far if you know about auto-increment.
How can I turn this on? All I can find are scripts for table creation. I'd like to keep my existing table and simply edit it.
How is your Linq-to-SQL model defined?? Check the properties of the user_id column - what are they set to??
In your Linq-to-SQL model, be sure to have Auto Generated Value set to true, Auto-Sync set to OnInsert, and the server data type should also match your settings (INT IDENTITY),
In SQL Server Management Studio, you need to define the user_id column to be of type INT IDENTITY - in the visual table designer, you need to set this property here:
It is zero because you have a integer for a primary key column type. To use auto-increment, set tables identity column to the ID (selected in the table properties)
Would probably be easier to edit the database using VS if you have a version that will work for, otherwise if you have to edit it in management studio see this article:
http://blogs.msdn.com/b/sqlexpress/archive/2006/11/22/connecting-to-sql-express-user-instances-in-management-studio.aspx
Or you can increment the user_id manually and pass it to the insert function if you cannot alter the property/table field description

Turn off IDENTITY_INSERT for Dataset insert

I am using a dataset to insert data being converted from an older database. The requirement is to maintain the current Order_ID numbers.
I've tried using:
SET IDENTITY_INSERT orders ON;
This works when I'm in SqlServer Management Studio, I am able to successfully
INSERT INTO orders (order_Id, ...) VALUES ( 1, ...);
However, it does not allow me to do it via the dataset insert that I'm using in my conversion script. Which looks basically like this:
dsOrders.Insert(oldorderId, ...);
I've run the SQL (SET IDENTITY_INSERT orders ON) during the process too. I know that I can only do this against one table at a time and I am.
I keep getting this exception:
Exception when attempting to insert a value into the orders table
System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'orders' when IDENTITY_INSERT is set to OFF.
Any ideas?
Update
AlexS & AlexKuznetsov have mentioned that Set Identity_Insert is a connection level setting, however, when I look at the SQL in SqlProfiler, I notice several commands.
First - SET IDENTITY_INSERT DEAL ON
Second - exec sp_reset_connection
Third to n - my various sql commands including select & insert's
There is always an exec sp_reset_connection between the commands though, I believe that this is responsible for the loss of value on the Identity_Insert setting.
Is there a way to stop my dataset from doing the connection reset?
You have the options mixed up:
SET IDENTITY_INSERT orders ON
will turn ON the ability to insert specific values (that you specify) into a table with an IDENTITY column.
SET IDENTITY_INSERT orders OFF
Turns that behavior OFF again and the normal behavior (you can't specify values for IDENTITY columns since they are auto-generated) is reinstated.
Marc
You want to do SET IDENTITY_INSERT ON to allow you to insert into identity columns.
It seems a bit backwards, but that's the way it works.
It seems that you're doing everything right: SET IDENTITY_INSERT orders ON is the right way on SQL Server's side. But the problem is that you're using datasets. From the code you've provided I can say that you're using typed dataset - the one that was generated in Visual Studio based on the database.
If this is the case (most likely) then this dataset contains a constraint that does not allows you to set values for orderId field, i.e. it's the code that does not allow specifying explicit value, not SQL Server. You should go to dataset designer and edit properties of orderId field: set AutoIncrement and ReadOnly to false. But the same changes can be performed in run time. This will allow you to add a row with explicit value for orderId to a dataset and later save it to SQL Server table (you will still need SET IDENTITY_INSERT).
Also note that IDENTITY_INSERT is a connection-level setting so you need to be sure that you're executing corresponding SET exactly for the same connection that you will be using to save your changes to the database.
I would use Profiler to determine whether your SET IDENTITY_INSERT orders ON;
is issued from the same connection as your subsequent inserts, as well as the exact SQL being executed during inserts.
AlexS was correct, the problem was the Insert_Identity worked, but it is a connection level setting, so I needed to set the Insert_Identity within a transaction.
I used Ryan Whitaker's TableAdapterHelper code
and I created an update command on my tableadapter that ran the Identity_Insert. I then had to create a new Insert command with the Identity column specified. I then ran this code
SqlTransaction transaction = null;
try
{
using (myTableAdapter myAdapter = new myTableAdapter())
{
transaction = TableAdapterHelper.BeginTransaction(myAdapter);
myAdapter.SetIdentityInsert();
myAdapter.Insert(myPK,myColumn1,myColumn2,...);
}
transaction.Commit();
}
catch(Exception ex)
{
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
In case that you still have problems with "insert_identity" , you can try to use a complete insert statement like:
insert into User(Id, Name) values (1,'jeff')

How can I change a field in a SQL server database that's set to "Read Only Cell"?

I have a SQL database that has a table with a field set to "Read Only" when I look at it through Microsoft SQL Server Management Studio Express.
I need to change some data within that field manually but I can't see any properties that I can change that will let me override this.
Will I need to write a sql script on the table to do this or is there something that I am missing ?
What is the datatype of the field? You may not be able to "type" into it if its of an ntext or image datatype and management studio can't handle the size of it.
In that case you might have no option but to perform an update as follows.
UPDATE TableName SET ColumnName = 'NewValue' WHERE PrimaryKeyId = PrimaryKeyValue
The field is most likely "read-only" because it contains a calculated value.
If that's the case, you would have to change calculation in the table definition to change it's value.
This problem will occur when you set a particular field as Primary Key and you set it into 'Is Identity' is true, that means that field will automatically incremented whenever an insertion is takes placed...So better to check whether it is auto increment or not.. If it is ,then change that property 'Is Idenitity' as false.
In an SQL query I had once, the query I used to generate the table to edit included a join to a table on a "Server Object", specifically a linked server. This marked the cells as read only, even though the table on which I was actually going to change the data wasn't on the linked server.
My resolution: Luckily I was able to adjust the query so I didn't need to do the JOIN with a linked table and then I could edit the cells.
Suggestion: Check your query for linked servers or other odd statements that may lock your table.
Use trigger in order to prevent this column updating:
CREATE TRIGGER UpdateRecord ON my_table
AFTER UPDATE AS UPDATE my_table
SET [CreatedDate] = ((SELECT TOP 1 [CreatedDate] FROM Deleted d where d.[id]=[id]))

Resources