Сопоставить значение идентификатора с объектом после оператора слияния - PullRequest
0 голосов
/ 22 февраля 2019

У меня есть таблица с именем People со следующей схемой:

Id           INT NOT NULL IDENTITY(1, 1)
FirstName    NVARCHAR(64) NOT NULL
LastName     NVARCHAR964) NOT NULL

Я использую запрос, подобный этому, для выполнения вставок и обновлений в одном запросе:

MERGE INTO People AS TARGET
USING ( VALUES
    (@id0, @firstName0, @lastname0),
    (@id1, @firstName1, @lastname1)
    ...
) AS SOURCE ([Id],[FirstName],[LastName])
ON TARGET.[Id] = SOURCE.[Id]
WHEN MATCHED BY TARGET THEN
    UPDATE SET
        [FirstName] = SOURCE.[FirstName],
        [LastName] = SOURCE.[LastName]
WHEN NOT MATCHED BY TARGET THEN
    INSERT ([FirstName],[LastName])
    VALUES ([FirstName],[LastName])
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
OUTPUT $action, INSERTED.*;

MyПриложение структурировано так, что клиент перезванивает на сервер для загрузки существующего состояния приложения.Затем клиент создает / изменяет / удаляет объекты локально и передает эти изменения на сервер в виде одной связки.

Вот пример того, как мой код "SaveEntities" в настоящее время выглядит:

public void SavePeople(IEnumerable<Person> people)
{
    // Returns the query I mentioned above
    var query = GetMergeStatement(people);

    using(var command = new SqlCommand(query))
    {
        using(var reader = command.ExecuteReader())
        {
            while(reader.Read())
            {
                // how do I tie these records back to
                // the objects in the people collection?
            }
        }
    }
}

Я могу использовать значение в столбце $action, чтобы отфильтровать до просто ВСТАВЛЕННЫХ записей.INSERTED.* возвращает все столбцы в TARGET для вставленной записи.Проблема в том, что у меня нет способа четко связать эти результаты с набором объектов, переданных в этот метод.

Единственное решение, о котором я мог подумать, - это добавить в таблицу столбец GUID с возможностью записи и разрешить MERGE.оператор, чтобы указать это значение, чтобы я мог ссылаться на эти объекты в коде, используя его, и назначить оттуда значение идентификатора, но кажется, что это противоречит цели иметь столбец автоматической идентификации и выглядит запутанным.

IМне действительно любопытно, как это может работать, потому что я знаю, что Entity Framework делает что-то, чтобы смягчить эту проблему (чтобы было ясно, я думаю, что мне пришлось бы столкнуться с той же проблемой, если бы я использовал чистый оператор INSERT вместо MERGE).В EF я могу добавлять объекты в модель, вызывать Entity.SaveChanges() и автоматически обновлять свойство идентификатора объекта, используя магию.Я думаю, что это та магия, которую я хочу понять больше.

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

1 Ответ

0 голосов
/ 22 февраля 2019

Одна вещь, которая мне нравится в операторе MERGE, заключается в том, что исходные данные находятся в области действия в предложении OUTPUT.

OUTPUT $action, SOURCE.Id, INSERTED.Id;

При вставке это даст вам три столбца: 'INSERT 'в первом, значения @id0 и @id1 во втором и совпадающие, недавно вставленные Id значения в третьем.

В вашем коде C # просто читайте строки какВы обычно делаете это.

while (reader.Read())
{
    string action = reader.GetString(0);
    if (action == "INSERT")
    {
        int oldId = reader.GetInt32(1);
        int newId = reader.GetInt32(2);

        // Now do what you want with them.
    }
}

Вы также можете проверить «УДАЛИТЬ» и «ОБНОВИТЬ», но имейте в виду, что порядковый номер 2 будет «1014 *» в «УДАЛИТЬ», поэтому вам необходимо убедиться, что вы проверилидля этого перед вызовом reader.GetInt32 в этом случае.

Я использовал это в сочетании с табличными переменными (OUTPUT SOURCE.Id, INSERTED.Id INTO @PersonMap ([OldId], [NewId])), чтобы копировать иерархии 4 и 5 таблиц глубиной, все со столбцами идентификаторов.

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