简体   繁体   English

在Ado.net C中动态构建Where子句#

[英]Build Where Clause Dynamically in Ado.net C#

I will be taking in around 1000 records at a given time and I have to determine if they are existing records or new records. 我将在给定时间内收集大约1000条记录,我必须确定它们是现有记录还是新记录。

If they are existing I have to update the records, if new then just insert them. 如果它们存在,我必须更新记录,如果是新的,则只需插入它们。 I will not know if any of them will be existing or if they all will be existing. 我不知道他们中的任何一个是否存在,或者它们是否都存在。

I thought that it might be best to do one query to the database and try to find if any of them exist in the db and store them in memory and check that collection in memory and check that. 我认为最好对数据库进行一次查询并尝试查找数据库中是否存在任何查询并将其存储在内存中并检查该内存中的集合并检查它。

Originally I was told I 1 field would be enough to determine uniqueness. 最初我被告知我1场将足以确定唯一性。 So I thought I could just do 1 big in clause against 1 field in the database but now I found out that is not the case and I need to use 3 fields to determine if the record is existing or now. 所以我想我可以在数据库中对1个字段做一个大的子句,但现在我发现情况并非如此,我需要使用3个字段来确定记录是存在还是现在。

This is basically an and clause 这基本上是一个和条款

select * from where columnA = "1" and ColumnB = "2" and ColumnC = "3"

How can I properly right this in C# ado.net? 我怎样才能在C#ado.net中正确地理解这一点?

I am guessing I going to need to have like some super where clause? 我猜我需要有一些超级where子句?

select * from where (columnA = "1" and ColumnB = "2" and ColumnC = "3") or  (columnA = "4" and ColumnB = "5" and ColumnC = "6") or [....998 more conditional clauses)

I am open to better ideas if possible. 如果可能的话,我愿意接受更好的想法。 I still think doing it in 1 shot is better than doing 1000 separate queries. 我仍然认为一次性完成它比做1000次单独查询更好。

I can only help you to write query for your request 我只能帮助您为您的请求编写查询

        var recordCount = 1000;
        var query = "SELECT * FROM TableName WHERE";
        for (var i = 1; i < recordCount - 2; i += 3)
        {
            query += " (columnA = " + i + " and ColumnB = " + (i + 1) + " and ColumnC = " + (i + 2) + ") or ";
        }

I feel kinda silly writing this answer, because I think that you should be able to put the pieces together a complete answer from other posts - but this is not an exact duplicate of either of the questions I have in mind. 我觉得写这个答案有点傻,因为我认为你应该能够把这些文章从其他帖子中完整地回答 - 但这并不是我想到的任何一个问题的完全重复。

There already are questions and answers in Stackoverflow dealing with this issue - however in my search I only found answers that are not thread safe, and most of them are using merge . Stackoverflow中已经有问题和答案处理这个问题 - 但是在我的搜索中我只找到了非线程安全的答案,而且大多数答案都是使用merge

There are different questions and answers I can refer you to such as my answer to Adding multiple parameterized variables to a database in c# where you can see how to work with table valued parameters on c#, and to Aaron Bertrand's answer to Using a if condition in an insert SQL Server where you can see how to create a safe upsert - however I didn't find any answer that covers this completely - so here you go: 我可以向您推荐不同的问题和答案,例如我在c#向数据库添加多个参数化变量的答案,您可以在c#中查看如何使用表值参数,以及Aaron Bertrand对使用if条件的回答插入SQL Server ,你可以看到如何创建一个安全的upsert - 但是我没有找到任何完全覆盖这个的答案 - 所以你去:

First you need to create a user defined table type in your database: 首先,您需要在数据库中创建用户定义的表类型:

CERATE TYPE MyTableType AS TABLE
(
     Column1 int NOT NULL,
     Column2 int NOT NULL,
     Column3 int NOT NULL,
     -- rest of the columns in your table goes here
     PRIMARY KEY (Column1, Column2, Column3)
)

Then, you create the stored procedure: 然后,您创建存储过程:

CREATE stp_UpsertMyTable
(
    @MyTableType dbo.MyTableType readonly -- table valued parameters must be readonly
)
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

BEGIN TRANSACTION;

UPDATE t 
SET t.column4 = tvp.column4,
    t.column5 = tvp.column5 -- and so on for all columns that are not part of the key
FROM dbo.MyTable AS t
INNER JOIN @MyTableType AS tvp
    ON t.Column1 = tvp.Column1
    AND t.Column2 = tvp.Column2
    AND t.Column3 = tvp.Column3;

 -- Note: <ColumnsList> should be replaced with the actual columns in the table
INSERT dbo.MyTable(<ColumnsList>)
  SELECT <ColumnsList>
  FROM @MyTableType AS tvp
  WHERE NOT EXISTS
  (
    SELECT 1 FROM dbo.MyTable t
    WHERE t.Column1 = tvp.Column1
    AND t.Column2 = tvp.Column2
    AND t.Column3 = tvp.Column3
  );

COMMIT TRANSACTION;

GO

Then, the c# part is simple: 然后,c#部分很简单:

DataTable dt = new DataTable();
dt.Columns.Add("Column1", typeof(int));
dt.Columns.Add("Column2", typeof(int));
dt.Columns.Add("Column3", typeof(int));
dt.Columns.Add("Column4", typeof(string));
dt.Columns.Add("Column5", typeof(string));

// Fill your data table here

using (var con = new SqlConnection("ConnectionString"))
{
    using(var cmd = new SqlCommand("stp_UpsertMyTable", con))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@MyTable", SqlDbType.Structured).Value = dt;
        con.Open();
        cmd.ExecuteNonQuery();
    }
}

Now you have a complete and safe upsert using a table valued parameter with only one round trip between c# and sql server. 现在,您可以使用表值参数进行完整且安全的upsert,在c#和sql server之间只进行一次往返。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM