2012-03-26 3 views
0

Скажем, у меня есть две таблицыTSQL Вставка данных Linked внешнего ключа

RDB_DataEntities

DataEntityId 
Name 
Created 
Modified 
... 

RDB_DataInstances

DataInstanceId 
DataEntityId 

Так RDB_DataInstances присоединяется к RDB_DataEntities через внешний ключ на их колонках DataEntityId.

Предположим, я хочу вставить данные в обе таблицы в одну и ту же транзакцию. Код у меня есть для этого заключается в следующем:

using (var con = new SqlConnection("data source=speedy;initial catalog=mydb;user id=myuser;password=mypass")) 
{ 
    con.Open(); 

    using (var tran = con.BeginTransaction()) 
    { 
     SqlCommand i1 = new SqlCommand("insert into RDB_DataEntities (Name,IsSchema,Created,Modified,RequireCaptcha,UniqueByEmail,UniqueByMac) values ('hi',0,GetDate(),GetDate(),0,0,0)", con, tran); 

     i1.ExecuteNonQuery(); 

     SqlCommand i2 = new SqlCommand("select SCOPE_IDENTITY() as newid", con, tran); 
     var id = int.Parse(i2.ExecuteScalar().ToString()); 

     SqlCommand i3 = new SqlCommand("insert into RDB_DataInstances (DataEntityId) values (" + id + ")", con, tran); 
     i3.ExecuteScalar(); 
     tran.Commit(); 
    } 
} 

Почему метание ошибки внешнего ключа

INSERT заявление противоречило с ограничением внешнего ключа «FK_RDB_DataInstances_RDB_DataEntities». Конфликт произошел в базе данных «NMSS_CMS», таблице «dbo.RDB_DataEntities», в столбце «DataEntityId».

Не должно ли транзакция знать, что я вставляю внешний ключ на основе вставки, которую я только что сделал в контексте текущей транзакции? Я в отъезде?

Как вы это делаете?

+0

Это не происходит на вашем первом «INSERT», не так ли? То есть, вы не настроили FK неправильно ... –

ответ

1

Потому что SCOPE_IDENTITY() не работает, если вы используете два разных контекста команд (по определению это отдельная область). Вы можете добавить второй запрос на первый, и запустить ExecuteScalar(), например, так:

SqlCommand i1 = new SqlCommand("insert into RDB_DataEntities (Name,IsSchema,Created,Modified,RequireCaptcha,UniqueByEmail,UniqueByMac) values ('hi',0,GetDate(),GetDate(),0,0,0);select SCOPE_IDENTITY() as newid;",con,tran);     
var id=int.Parse(i1.ExecuteScalar().ToString()); 

Edit: Просто хотел бросить вместе версию T-SQL, что происходит.

DECLARE @newid int 

BEGIN TRANSACTION 

insert into RDB_DataEntities 
    (Name,IsSchema,Created,Modified,RequireCaptcha,UniqueByEmail,UniqueByMac) 
values 
    ('hi',0,GetDate(),GetDate(),0,0,0) 

SELECT @newid = SCOPE_IDENTITY() 

insert into RDB_DataInstances 
    (DataEntityId) 
values 
    (@newid) 

COMMIT TRANSACTION 
+2

Другое решение: используйте предложение вывода. Сохраняет запрос. –

+0

SCOPE_IDENTITY() определенно работает в обоих направлениях. Я отлаживал, чтобы гарантировать, что мой идентификатор var определенно имеет целочисленное значение. – Micah

+0

Если вы возвращаете правильное значение, то я согласен, что он должен работать.Версия T-SQL того, что вы пытаетесь сделать, имеет логический смысл. – mgnoonan

0

Вот 2 возможных решения для вас, если я понял вашу проблему:

  1. Вы можете установить уровень изоляции транзакций и использовать чтение незафиксированных/NOLOCK для выполнения грязного чтения на ранее вставленный запись в сделке (см этот пост для более Why use a READ UNCOMMITTED isolation level?)

  2. Вы можете просто создать Guid в коде и вручную вставить в 2 таблицы в качестве параметра SqlCommand, а не с помощью SCOPE_IDENTITY() после первая вставка. (Мой предпочтительный вариант)

0

Я сбросил внешний ключ и воссоздал его, и он начал работать.

Смежные вопросы