tags:

views:

214

answers:

2

Hi, is there a way of knowing ID of identity column of record inserted via InsertOnSubmit beforehand, e.g. before calling datasource's SubmitChanges?

Imagine I'm populating some kind of hierarchy in the database, but I wouldn't want to submit changes on each recursive call of each child node (e.g. if I had Directories table and Files table and am recreating my filesystem structure in the database).

I'd like to do it that way, so I create a Directory object, set its name and attributes, then InsertOnSubmit it into DataContext.Directories collection, then reference Directory.ID in its child Files. Currently I need to call InsertOnSubmit to insert the 'directory' into the database and the database mapping fills its ID column. But this creates a lot of transactions and accesses to database and I imagine that if I did this inserting in a batch, the performance would be better.

What I'd like to do is to somehow use Directory.ID before commiting changes, create all my File and Directory objects in advance and then do a big submit that puts all stuff into database. I'm also open to solving this problem via a stored procedure, I assume the performance would be even better if all operations would be done directly in the database.

+1  A: 

Not sure off the top if there is a way to run a straight SQL query in LINQ, but this query will return the current identity value of the specified table.

USE [database];
GO
DBCC CHECKIDENT ("schema.table", NORESEED);
GO
ryanulit
thanks, but i might generate thousands of records in one batch, and even on few different threads, so the identity column values would mix up.I thought of turning off automatic identity generating, but then I realized that I might run more than one such query at once and I wouldn't be able to reliably generate identity values on my own.
Axarydax
Yea I misunderstood you at first. I thought you were just talking one directory object at a time with many files, but you actually want many directories and many files at a time.
ryanulit
+2  A: 

One way to get around this is to not use an identity column. Instead build an IdService that you can use in the code to get a new Id each time a Directory object is created.

You can implement the IdService by having a table that stores the last id used. When the service starts up have it grab that number. The service can then increment away while Directory objects are created and then update the table with the new last id used at the end of the run. Alternatively, and a bit safer, when the service starts up have it grab the last id used and then update the last id used in the table by adding 1000 (for example). Then let it increment away. If it uses 1000 ids then have it grab the next 1000 and update the last id used table. Worst case is you waste some ids, but if you use a bigint you aren't ever going to care.

Since the Directory id is now controlled in code you can use it with child objects like Files prior to writing to the database.

Simply putting a lock around id acquisition makes this safe to use across multiple threads. I've been using this in a situation like yours. We're generating a ton of objects in memory across multiple threads and saving them in batches.

This blog post will give you a good start on saving batches in Linq to SQL.

Mike Two