Entity Framework 4 и транзакции: влияют ли незафиксированные изменения на выбранные результаты транзакции? - PullRequest
0 голосов
/ 21 марта 2011

Если я буду использовать транзакции с Entity Framework 4 следующим образом, будет ли выбор в измененном наборе отражать вновь сохраненные идентификаторы клиентов в рамках транзакции, или это будет генерировать один и тот же идентификатор для каждого клиента?

using ( System.Data.Common.DbTransaction trans = new DbTransaction() )
{
    foreach( var customer in CustomersToSave )
    {  
        // Calculate lowest ID available
        var id_Query =  (from c in Customers
                     select c.ID).Distinct();
        var lowest_ID_Available = 
            (from p1 in id_Query
             from p2 in id_Query.Where(a => a == p1 + 1).DefaultIfEmpty()
             where p2 == 0
             select p1).Min();

        ... Create a customer with the lowest_ID_Available
    }

    trans.Commit()
}

1 Ответ

2 голосов
/ 22 марта 2011

Это будет работать, только если вы наберете SaveChanges после добавления каждого клиента, что является довольно плохим решением. Также это не будет выполняться в транзакции, потому что DbTransaction само по себе не будет работать, пока не будет создано из DbConnection путем вызова BeginTransaction. Вместо этого используйте TransactionScope.

Другая проблема - это параллелизм. В зависимости от уровня изоляции вашей транзакции другие параллельные транзакции либо будут ждать завершения этой транзакции, либо смогут использовать те же идентификаторы, что и текущая транзакция.

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

Использование этой процедуры зависит от ваших требований. Если вам требуется непрерывная последовательность сгенерированных чисел (без дырок от откатов), то вы должны заблокировать запись в этой специальной таблице только для текущей транзакции. Если вам требуется только получить уникальный номер, но вам не нужно иметь последовательность без дырок, вы можете использовать параллельный доступ.

Пример хранимой процедуры, блокирующей запись (если вам не нужна блокировка, удалите подсказки в операторе обновления):

CREATE PROCEDURE [dbo].[GetNextSequenceValue]
    @SequenceType VARCHAR(20)
AS
BEGIN
    DECLARE @Result INT

    UPDATE [dbo].[Sequences] WITH (ROWLOCK, UPDLOCK)
    SET @Result = Value = Value + 1
    WHERE SequenceType = @SequenceType

    RETURN @Result
END
...