Как получить предложение where на вставку или обновление в Linq для Sql? - PullRequest
3 голосов
/ 19 апреля 2010

Я пытаюсь преобразовать следующий хранимый процесс в вызов LinqToSql (это упрощенная версия SQL):

INSERT INTO [MyTable]
    ([Name], [Value])
SELECT
    @name, @value
WHERE
   NOT EXISTS(SELECT [Value] FROM [MyTable] WHERE [Value] = @value)

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

using (TransactionScope scope = new TransactionScope())
{
    if (Context.MyTables.SingleOrDefault(t => t.Value == in.Value) != null)
    {
        MyLinqModels.MyTable t = new MyLinqModels.MyTable()
        {
           Name = in.Name,
           Value = in.Value
        };

        // Do some stuff in the transaction

        scope.Complete();
    }
}

Это первый раз, когда я действительно столкнулся с этим сценарием, поэтому я хочу убедиться, что я поступаю правильно. Кажется ли это правильным или кто-то может предложить лучший способ сделать это без двух отдельных вызовов?

Редактировать: Я сталкиваюсь с подобной проблемой с обновлением:

UPDATE [AnotherTable]
SET [Code] = @code
WHERE [ID] = @id AND [Code] IS NULL

Как бы я сделал такую ​​же проверку с Linqtosql? Я предполагаю, что мне нужно выполнить get, а затем установить все значения и отправить, но что, если кто-то обновит [Code] что-то отличное от null с того времени, когда я получаю get, когда выполняется обновление?

Та же проблема, что и при вставке ...

Ответы [ 3 ]

1 голос
/ 19 апреля 2010

Я не верю, что это возможно с LINQ-to-SQL, но лучше было бы использовать Any() вместо SingleOrDefault():

using (TransactionScope scope = new TransactionScope())
{
    if (!Context.MyTables.Any(t => t.Value == in.Value))
    {
        MyLinqModels.MyTable t = new MyLinqModels.MyTable()
        {
           Name = in.Name,
           Value = in.Value
        };

        // Do some stuff in the transaction

        scope.Complete();
    }
}

Я полагаю, Any() использует ключевое слово EXISTS в SQL, которое выбирает логическое значение вместо полного содержимого всех столбцов в этой строке.

Предложение Аарона об использовании хранимой процедуры, вероятно, было бы более простым - и вы можете также связать его с вашим текстовым текстом.

1 голос
/ 19 апреля 2010

Заключение в TransactionScope на самом деле не предотвращает конфликты, если в базе данных нет уникальных ограничений. Это гарантирует только атомарность этой транзакции.

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

Честно говоря, исходя из ваших требований, я бы рекомендовал делать это с помощью хранимой процедуры. Linq to SQL - отличный инструмент, но он не может сделать всего , что может SQL; похоже, это один из тех случаев, когда вам нужно больше контроля, чем может дать вам L2S.

1 голос
/ 19 апреля 2010

Если это неожиданный случай (т. Е. Указывает на ошибку), должно быть достаточно ограничения UNIQUE.

Нет прямого способа сделать эточерез LINQ-to-SQL, поэтому ваш TransactionScope (или SqlTransaction для переданного соединения) - это жизнеспособный механизм.Другой может быть триггером вместо триггера или хранимой процедурой для выполнения INSERT.

То, что у вас, вероятно, самое простое;посмотреть, достаточно ли это быстро (у него есть дополнительный круговой оборот) и придерживаться его?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...