SQL Compact Edition批量更新

SQL Compact Edition批量更新,sql,sql-server-ce,entity-framework-6,Sql,Sql Server Ce,Entity Framework 6,我目前正在使用实体框架,需要定期更新多个实体 我需要做的是添加一个日志号,它基于几个不同的表。使用SQL Server,我可以使用一个具有内部和外部联接、GROUP BY和ROW_NUMBER的存储过程,它为我完成了繁重的工作,而且非常高效 请参见以下程序代码: CREATE PROCEDURE [dbo].[sp_UpdateNumber] @RefId int AS BEGIN UPDATE TableWithNumber SET Nmr = other.Nmr

我目前正在使用实体框架,需要定期更新多个实体

我需要做的是添加一个日志号,它基于几个不同的表。使用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();

我想知道在SQL CE中更新实体列表是否有比在foreach循环中调用ExecuteSqlCommand更快或更有效的方法?

如果您的业务逻辑允许您逐行更新多个表中的数据,而不是使用复杂的SQL命令,您可以尝试表直接方法。它包括以下步骤

创建连接字符串指向SDF文件的SqlCeConnection对象。使用命令类型CommandType.TableDirect为此连接创建SqlCeCommand对象。使用选项ResultSetOptions.Updateable和ResultSetOptions.Scrollable创建SqlCeResultSet


现在您可以使用Seek、Read和update方法更新表行。这种方法可能是最快的方法。但它需要编写比传统EF方法多得多的代码。

我能找到的唯一改进是在foreach循环之前准备SqlCeCommand,然后在循环中只更改现有参数的值。但是,在SQL CE中,更新非常有限。如果需要在可嵌入数据库中存储过程和触发器,请考虑。LoalDB将是非常好的,并且希望使用它。然而,我们的应用程序的一个关键要求是,它应该是可部署的拷贝/过去,并且不需要安装例程。由于LocalDB需要在客户端上进行设置,不幸的是,它不是一个选项。再一次,我很想用它。
    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));
    }