[英]Update database table records based on array of data
我有一个像这样的对象数组:
[ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 2}]
我的访问表设计:
访问ID | 用户身份 | 来源_ID |
---|---|---|
1 | 1 | 1 |
2 | 1 | 2 |
3 | 2 | 1 |
4 | 2 | 2 |
如果我想将 User_ID = 1 的访问记录更新为 [ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 3} ]
如何删除访问记录“User_ID = 1,Source_ID = 2”并插入访问记录“User_ID = 1,Source_ID = 3”,但保留“User_ID = 1,Source_ID = 1”记录。
使用存储过程?
到目前为止我所拥有的:
C#:
...Create the DB Command and add parameter "Source_ID"..
foreach (var SourceID in user.SourceAccess)
{
dBCall1.GetCommand().Parameters["Source_ID"].Value = SourceID;
dBCall1.ExecuteNonQuery;
}
存储过程:
CREATE PROCEDURE [dbo].[UpdateUserSourceAccess]
@UserID INT,
@SourceID INT
AS
IF NOT EXISTS (SELECT 1 FROM [UserSourceAccess] WHERE [User_ID] = @UserID AND Source_ID = @SourceID)
INSERT INTO UserSourceAccess
( UserID, SourceID ) VALUES ( @UserID, @SourceID )
...
您尝试做的问题是您需要能够比较每个用户的Source_ID
的完整列表,并根据需要插入或删除。
为此,您需要有完整列表进行比较的过程,因此最好传入表值参数。 为此,我通常会保留一些标准的表类型:
CREATE TYPE IdList (Id int PRIMARY KEY);
GO
然后你需要做一个部分MERGE
:换句话说,不要MERGE
整个表,因为那样任何其他用户都会删除他们的所有行。 而是使用 CTE 预过滤目标表。 然后我们可以针对 CTE 进行MERGE
,与表参数进行比较。
CREATE OR ALTER PROCEDURE [dbo].[UpdateUserSourceAccess]
@UserID int,
@SourceIDs dbo.IdList
AS
SET NOCOUNT ON;
WITH t AS (
SELECT t.AccessID, t.User_ID, t.Source_ID
FROM YourTable t
WHERE t.User_ID = @UserID
)
MERGE INTO t
USING @SourceIDs s
ON s.Id = t.Source_ID
WHEN NOT MATCHED BY SOURCE
THEN DELETE
WHEN NOT MATCHED BY TARGET
THEN INSERT (User_ID, Source_ID)
VALUES (@UserID, s.val)
;
GO
你可以像这样从 C# 调用它
using(var comm = new SqlCommand("UpdateUserSourceAccess", yourConnection))
{
var table = new DataTable { Columns = { { "Id", typeof(int) } } };
foreach (var SourceID in user.SourceAccess)
table.Rows.Add(SourceID);
comm.Parameters.Add(new SqlParameter("@SourceIDs", SqlDbType.Structured)
{
TypeName = "dbo.IdList",
Direction = ParameterDirection.Input,
Value = table
});
comm.ExecuteNonQuery;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.