[英]Update database table records based on array of data
I have an array of objects like this:我有一个像这样的对象数组:
[ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 2}] [ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 2}]
And my access table design:我的访问表设计:
AccessID![]() |
User_ID![]() |
Source_ID![]() |
---|---|---|
1 ![]() |
1 ![]() |
1 ![]() |
2 ![]() |
1 ![]() |
2 ![]() |
3 ![]() |
2 ![]() |
1 ![]() |
4 ![]() |
2 ![]() |
2 ![]() |
If I want to update the access records for User_ID = 1 to [ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 3} ]如果我想将 User_ID = 1 的访问记录更新为 [ {User_ID: 1, Source_ID: 1}, {User_ID: 1, Source_ID: 3} ]
How can I Remove the access record "User_ID = 1, Source_ID = 2" And Insert the access record "User_ID = 1, Source_ID = 3", but keep the "User_ID = 1, Source_ID = 1" record.如何删除访问记录“User_ID = 1,Source_ID = 2”并插入访问记录“User_ID = 1,Source_ID = 3”,但保留“User_ID = 1,Source_ID = 1”记录。
Using stored procedure?使用存储过程?
What I have so far:到目前为止我所拥有的:
C#: 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;
}
Stored Procedure:存储过程:
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 )
...
The problem with what you are trying to do, is that you need to be able to compare a full list of Source_ID
per user, and insert or delete as necessary.您尝试做的问题是您需要能够比较每个用户的
Source_ID
的完整列表,并根据需要插入或删除。
For this to work, you need the procedure to have the full list to compare, so you are best off passing in a Table-Valued Parameter.为此,您需要有完整列表进行比较的过程,因此最好传入表值参数。 I usually keep a few standard table-types for this purpose:
为此,我通常会保留一些标准的表类型:
CREATE TYPE IdList (Id int PRIMARY KEY);
GO
Then you need to do a partial MERGE
: in other words do not MERGE
the full table, because then any other users will get all their rows deleted.然后你需要做一个部分
MERGE
:换句话说,不要MERGE
整个表,因为那样任何其他用户都会删除他们的所有行。 Instead pre-filter the target table with a CTE.而是使用 CTE 预过滤目标表。 We can then
MERGE
against the CTE, comparing against the table parameter.然后我们可以针对 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
You can call it from C# like this你可以像这样从 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.