I have a table with the primary key as the identity column. I'm doing an insert with linq-to-sql and I was wondering if there's a way to return the ID of the row that was inserted and how we know for sure that the insert happened.
Thanks for your suggestions.
The primary key property of the entity that was used for the insert will be updated after the call to SubmitChanges with the ID from the database.
Ex:
using (var dc = new MyDataContext())
{
MyEntity entity = new MyEntity();
dc.MyEntities.InsertOnSubmit(entity);
dc.SubmitChanges();
int pkValue = entity.PKColumn
}
With LINQ-to-SQL it will update any IDENTITY (etc) properties during the save automatically, so just look at .Id (or whatever).
Re knowing it happened: updates etc happen in a transaction; that transaction must have committed to have got out of the method without an exception. If you have an outer TransactionScope (or similar) then that it up to you to commit; in short - until you do commit you have a phantom record. As such, avoid passing that new id anywhere until you have committed all your transactions.
The identity of the inserted record should automatically populate the object which was added to the DataContext for the insert. Just check the ID on that object.
Additionally, you can look at the GetChangeSet() method on the DataContext to see what changes it has tracked if you want more manual information about the number of affected records, etc..
Related
I'm trying to design a rollback changes system.
I'm tracking old record values when a record id modified or deleted and then I'm using that values to re-insert it when user choose to rollback it...
editions rollback are working as expected.
deletions are not... because when I attach the entity to DBContext it has the old Id but when I execute DbContext.SaveChanges(); the Id is replaced per a new one(Auto Incremented)
Here is the sample code:
var model = JsonConvert.DeserializeObject(oldValues.OldData, type);
DbSet mySet = this.Set(type);
mySet.Attach(model);
this.Entry(model).State = oldValues.AuditType == 0 ? EntityState.Modified : EntityState.Added;
base.SaveChanges();
into model.Id I can see the correct Id before save but after it EF changes it per a new one.
is there anyway to set temporally to keep the current Id instead of generate a new one?
I tried many solutions but none of them works.
Thanks
To disable the Auto Generated Id, you have to run this command in SQL:
SET IDENTITY_INSERT [<schema>].[<TableName>] ON;
Then you can insert whatever value you want for the PK, assuming it is still available. However, I don't think EF has a way to do this from code.
I'm not entirely sure this would work, but, in theory, you could run some ad-hoc SQL right before save-changes on a transaction you create and then see if EF will take it.
If that doesn't work, then try this:
ALTER TABLE theTableInQuestion AUTO_INCREMENT=1234
EIDT: Or try this approach:
How can I force entity framework to insert identity columns?
I currently have a table as defined as follows:
CREATE TABLE (
ID int identity(1,1) primary key not null,
field_one nvarchar(max) not null
)
I am using Entity framework 5 to insert records into this table. This aspect works and I am inserting records correctly.
field_one is a value based on the current id. For example if I have records where the max ID is 5, the next record would be inserted as (6,ABC6), and then (7, ABC7) and so on.
What I am running into is when the table is empty. The identity is at 7, and so the next record should be (8,ABC8). I Need to get the id of the auto_increment prior to the insert in order for me to apply the calculations I need when the table is empty.
How would I be able to do this since I know that the id is generated after the insert and the property is in my entity gets updated after.
You cannot get the correct identity before you perform SaveChanges. This is due to the fact that it is set by Entity Framework on insert.
However, there is a workaround to your problem.
Consider this:
// wrap in a transaction so that the entire operation
// either succeeds or fails as a whole
using(var scope = new TransactionScope())
using(var context = new DbContext()) {
var item = new Item();
context.Items.Add(item);
context.SaveChanges();
// item.ID now contains the identifier
item.field_one = string.Format("abc{0}", item.ID);
// perform another save.
context.SaveChanges();
// commit transaction
scope.Complete();
}
Yes, there are two calls to the database but there's no other way unless you are ready to go deeper than Entity Framework.
I am trying to write some content to my database via LINQ. Currently, I'm getting the following error:
Cannot insert explicit value for identity column in table 'MyTable' when IDENTITY_INSERT is set to OFF.
I understand this is a primary key related issue. My table has the identity specification set to "Yes" with Identity Increment set to "1". But I have successfully updated other tables using code that looks like the following:
using (DataModelDataContext context = new DataModelDataContext())
{
List<MyTable> newRecords = new List<MyTable>();
MyTable record1 = new MyTable();
record1.CreatedBy = GetUserName();
record1.Information = GetInformation();
newRecords.Add(record1);
MyTable record2 = new MyTable();
record2.CreatedBy = GetUserName();
record2.Information = GetInformation();
newRecords.Add(record2);
context.MyTables.InsertAllOnSubmit(newRecords);
context.SubmitChanges();
}
What would cause this error? If I want to write new records, is there a way to set the primary key before it gets sent to the db? Something like "GetNextKey()" or something? Basically, I just need to insert these records. What am I doing wrong?
Thanks!
The code you have posted would work, assuming neither of those fields have the identity value. You basically need to assure you do not try to set the identity value before you add the item to the Table collection. (actually, you should never set the identity value from your code in most circumstances when it is to be generated in the DB).
So somewhere, the code that is having an error is trying to set the identity field's value.
If the ID is important (say you're importing data, and records you'll be inserting later will reference these records), then turn off the identity temporarily while you perform the insert. If having a particular ID on each record doesn't matter, and you can let the identity column pick one (which is 99.9 percent of the time), make sure you're not specifying a value for the ID before trying to save the record. Also make sure that your mapping between the object and the DB specifies that the ID is an identity, so EF knows not to try to insert the ID column.
Check to make sure your primary key/identity column has the following set within the DBML:
Auto Generated Value: True
Auto-Sync: OnInsert
This will make sure that LINQ-To-SQL will not try and insert the key value into that column and that it will update the value after an insert takes place. These should be on when you added the table to the DBML.
I have a database with 'transactions' and 'transaction_lines'. A transaction has the basic shared details, and the transaction lines holds the values of components that make up the transaction. In traditional SQL, I'd use a SQL Transaction (Sorry, we have an ambiguous word now...) and then I'd INSERT INTO Transaction ... get the IDENTITY key value from the new row in the transaction table, then insert into my transaction_line table, using the identity column from the Transaction table as the foreign key.
Is there a good way to do this with linq?
Here's what I have so far:
account_transaction ac = new account_transaction
{
transaction_date = DateTime.Now,
is_credit = isCredit,
account = (db.accounts.FirstOrDefault(a => a.account_id == accountid))
};
db.AddToaccount_transaction(ac);
db.SaveChanges();
I think inbetween the 'AddToaccount_transaction(ac)' and the 'db.SaveChanges()', I need to add my transaction_lines.
You should just be able to create new transaction_line objects and set the foreign entity to ac. In LINQ-to-SQL, you work with entity objects instead of explicit keys. By setting the entity object to the ac object you will instruct the layer to determine what the key is and set it for you.
Answer above is correct but I would wrap it all in a TransactionScope. That way if any part of that query fails it will roll back the transaction. Just remember to call the scope.Complete() method prior to closing connection.
http://msdn.microsoft.com/en-us/library/ms251686(VS.80).aspx
so I have an old database that I'm migrating to a new one. The new one has a slightly different but mostly-compatible schema. Additionally, I want to renumber all tables from zero.
Currently I have been using a tool I wrote that manually retrieves the old record, inserts it into the new database, and updates a v2 ID field in the old database to show its corresponding ID location in the new database.
for example, I'm selecting from MV5.Posts and inserting into MV6.Posts. Upon the insert, I retrieve the ID of the new row in MV6.Posts and update it in the old MV5.Posts.MV6ID field.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually? I'm using SQL Server 2005, dev edition.
The key with migration is to do several things:
First, do not do anything without a current backup.
Second, if the keys will be changing, you need to store both the old and new in the new structure at least temporarily (Permanently if the key field is exposed to the users because they may be searching by it to get old records).
Next you need to have a thorough understanding of the relationships to child tables. If you change the key field all related tables must change as well. This is where having both old and new key stored comes in handy. If you forget to change any of them, the data will no longer be correct and will be useless. So this is a critical step.
Pick out some test cases of particularly complex data making sure to include one or more test cases for each related table. Store the existing values in work tables.
To start the migration you insert into the new table using a select from the old table. Depending on the amount of records, you may want to loop through batches (not one record at a time) to improve performance. If the new key is an identity, you simply put the value of the old key in its field and let the database create the new keys.
Then do the same with the related tables. Then use the old key value in the table to update the foreign key fields with something like:
Update t2
set fkfield = newkey
from table2 t2
join table1 t1 on t1.oldkey = t2.fkfield
Test your migration by running the test cases and comparing the data with what you stored from before the migration. It is utterly critical to thoroughly test migration data or you can't be sure the data is consistent with the old structure. Migration is a very complex action; it pays to take your time and do it very methodically and thoroughly.
Probably the simplest way would be to add a column on MV6.Posts for oldId, then insert all the records from the old table into the new table. Last, update the old table matching on oldId in the new table with something like:
UPDATE mv5.posts
SET newid = n.id
FROM mv5.posts o, mv6.posts n
WHERE o.id = n.oldid
You could clean up and drop the oldId column afterwards if you wanted to.
The best you can do that I know is with the output clause. Assuming you have SQL 2005 or 2008.
USE AdventureWorks;
GO
DECLARE #MyTableVar table( ScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());
It still would require a second pass to update the original table; however, it might help make your logic simpler. Do you need to update the source table? You could just store the new id's in a third cross reference table.
Heh. I remember doing this in a migration.
Putting the old_id in the new table makes both the update easier -- you can just do an insert into newtable select ... from oldtable, -- and the subsequent "stitching" of records easier. In the "stitch" you'll either update child tables' foreign keys in the insert, by doing a subselect on the new parent (insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild) or you'll insert children and do a separate update to fix the foreign keys.
Doing it in one insert is faster; doing it in a separate step meas that your inserts aren't order dependent, and can be re-done if necessary.
After the migration, you can either drop the old_id columns, or, if you have a case where the legacy system exposed the ids and so users used the keys as data, you can keep them to allow use lookup based on the old_id.
Indeed, if you have the foreign keys correctly defined, you can use systables/information-schema to generate your insert statements.
Is there a way to do this UPDATE via INSERT INTO SELECT FROM so I don't have to process every record manually?
Since you wouldn't want to do it manually, but automatically, create a trigger on MV6.Posts so that UPDATE occurs on MV5.Posts automatically when you insert into MV6.Posts.
And your trigger might look something like,
create trigger trg_MV6Posts
on MV6.Posts
after insert
as
begin
set identity_insert MV5.Posts on
update MV5.Posts
set ID = I.ID
from inserted I
set identity_insert MV5.Posts off
end
AFAIK, you cannot update two different tables with a single sql statement
You can however use triggers to achieve what you want to do.
Make a column in MV6.Post.OldMV5Id
make a
insert into MV6.Post
select .. from MV5.Post
then make an update of MV5.Post.MV6ID