Пакетное обновление SQL Compact Edition

В настоящее время я использую Entity Framework, и мне нужно регулярно обновлять множество сущностей.

Что мне нужно сделать, так это добавить номер журнала, который основан на нескольких разных таблицах. Используя SQL Server, я могу использовать хранимую процедуру с внутренними и внешними соединениями, GROUP BY и ROW_NUMBER, которая делает за меня тяжелую работу и также очень эффективна.

См. Код процедуры следующим образом:

CREATE PROCEDURE [dbo].[sp_UpdateNumber]
    @RefId int
AS
BEGIN
    UPDATE TableWithNumber 
    SET Nmr = other.Nmr
    FROM (
        SELECT MIN(C.Nmr) as Nmr, Z_ID
        FROM
        (
            SELECT 
                ROW_NUMBER() OVER (ORDER BY D.TicksCreatedOn, D.Z_Id, D.B_ID) as Nmr, D.*
                FROM (
                    SELECT 
                            S.Id as S_ID,
                            Z.Id as Z_ID,
                            B.Id as B_ID,
                            S.TicksCreatedOn
                    FROM 
                            ChildTable as B
                            INNER JOIN TableWithNumber Z on Z.ChildTableRefA_Id = B.Id
                            INNER JOIN ParentTable S on Z.ParentTable_Id = S.Id
                    WHERE S.Ref_Id = @RefId
                UNION
                    SELECT 
                            S.Id as S_ID,
                            Z.Id as Z_ID,
                            B.Id as B_ID,
                            S.TicksCreatedOn
                    FROM 
                            ChildTable as B
                            INNER JOIN TableWithNumber Z on Z.ChildTableRefB_Id = B.Id
                            INNER JOIN ParentTable S on Z.ParentTable_Id = S.Id
                    WHERE S.Ref_Id = @RefId) as D
        ) as C
    GROUP BY C.Z_ID) as other
    WHERE other.Z_ID = Id AND Ref_Id = @RefId
END

Из-за того, что хранимые процедуры недоступны в SQL Ce, и из-за дополнительных ограничений на то, как вы можете использовать GROUP BY в подвыборках, теперь мне нужно вычислить номер журнала в коде. Я использую SqlQuery в контексте, чтобы получить минимально необходимый набор данных, сгруппировать его и затем начать обновление для каждой сущности.

SELECT ZID
FROM
    (SELECT S.Id as [SID], Z.Id as [ZID], B.Id as [BID], S.TicksCreatedOn
    FROM ChildTable AS B
        INNER JOIN TableWithNumber as Z on Z.ChildTableRefA_Id = B.Id
        INNER JOIN ParentTable as S on Z.ParentTable_Id = S.Id
    WHERE S.Ref_Id = @RefId
    UNION
    SELECT S.Id as [SID], Z.Id as [ZID], B.Id as [BID], S.TicksCreatedOn
    FROM ChildTable AS B
        INNER JOIN TableWithNumber as Z on Z.ChildTableRefB_Id = B.Id
        INNER JOIN ParentTable as S on Z.ParentTable_Id = S.Id
        WHERE S.Ref_Id = @RefId) AS D
ORDER BY TicksCreatedOn, ZID, BID


        var result = Database.SqlQuery<NumberUpdate>(QUERY, new SqlCeParameter("@RefId", 1)).ToList();

Код в приложении выглядит примерно так

    var grouped = result
        .Select((x,y) => new NumberUpdate { ZID = x.ZID, Number = ++y })
        .GroupBy(x => x.ZID);

    foreach (var group in grouped)
    {
        Database.ExecuteSqlCommand("UPDATE TableWithNumber SET Number = @Nr WHERE Id = @Id",
            new SqlCeParameter("@Nr", group.Min(x => x.Number)),
            new SqlCeParameter("@Id", group.Key));
    }

Мне было интересно, есть ли более быстрый или более эффективный способ обновить список сущностей в SQL CE, чем вызов ExecuteSqlCommand в цикле foreach?


person Community    schedule 29.10.2014    source источник
comment
Единственное улучшение, которое я смог найти, - это подготовить SqlCeCommand перед циклом foreach, а затем внутри цикла изменить только значения существующих параметров. Но UPDATE очень ограничен в SQL CE.   -  person Vojtěch Dohnal    schedule 29.10.2014
comment
Если вам нужны хранимые процедуры и триггеры во встраиваемой базе данных, подумайте о LocalDB.   -  person Dour High Arch    schedule 29.10.2014
comment
LocalDB был бы ВЕЛИКОЛЕПНЫМ и хотел бы его использовать. Однако одним из важнейших требований к нашему приложению является то, что оно должно иметь возможность развертывания, копировать / прошивать и не требовать процедуры установки. Поскольку LocalDB требует настройки на клиенте, это, к сожалению, не вариант. Еще раз, мне бы очень понравилось его использовать.   -  person    schedule 29.10.2014


Ответы (1)


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

Создайте объект SqlCeConnection со строкой подключения, указывающей на ваш файл SDF. Создайте объект SqlCeCommand для этого соединения с типом команды CommandType.TableDirect. Создайте SqlCeResultSet с параметрами ResultSetOptions.Updatable и ResultSetOptions.Scrollable.

Теперь вы можете обновлять строки таблицы, используя методы Seek, Read и Update. Этот подход, возможно, является самым быстрым из возможных. Но для этого требуется написать гораздо больше кода, чем при традиционном подходе EF.

person mik61    schedule 24.12.2014