简体   繁体   中英

Delete multiple rows in PostgreSQL with Entity Framework using WHERE IN clause

I have a postgresql database and what I am trying to do is remove a bunch of rows from a table in as few queries as possible. So looping is not a good option. I am using NPGSQL for the postgres driver.

I have the code below but it is not working.

        string[] namesToDelete = PromosReplies.
                         PromosRepliesLoaded.GroupBy(pr => pr.Name).
                         Select(r=>r.Key).ToArray();
        long[] repliesIdsToDelete = context.PromosReplies.
                                    Where(pr => namesToDelete.Contains(pr.Name)).
                                    Select(r => r.Idx).ToArray();
        if (repliesIdsToDelete.Length > 0)
        {
          foreach (var name in namesToDelete)
          {
           context.Database.ExecuteSqlCommand("DELETE FROM messages WHERE name = {0}", name);
          }
            string idToDelete = String.Join(",", repliesIdsToDelete);
            int result = context.Database.ExecuteSqlCommand(
                 "DELETE FROM message_translations WHERE idx IN ({0})",
                 repliesIdsToDelete);

I get a "ERROR: 22P02: invalid input syntax for integer:" error when trying to execute the last query. Is there a way to overcome this? If yes can something similar be done with first delete statement where I have to use a string?

update I'm not working with EF, but here's the way to use array as parameter with Npgsql:

var cmd = NpgsqlCommand();
cmd.CommandText = "select * from test where id = any(@list)";
cmd.Connection = "**************************";
cmd.Parameters.Add("list", NpgsqlDbType.Array | NpgsqlDbType.Integer);
cmd.Connection.Open();
var r = cmd.ExecuteReader();

So I suppose in EF it would something like:

var par = new NpgsqlParameter("list", NpgsqlDbType.Array | NpgsqlDbType.Text);
var par.Value = namesToDelete;
int result1 = context.Database.ExecuteSqlCommand(
    "DELETE FROM messages WHERE name = any(@list)",
    par
);

old I don't like this one at all because it could lead to SQL injection:

int result1 = context.Database.ExecuteSqlCommand(
    String.Format(
        "DELETE FROM messages WHERE name in ({0})",
        String.Join(",", namesToDelete.Select(x => "'" + x + "'"))
    )
);

int result2 = context.Database.ExecuteSqlCommand(
    String.Format(
        "DELETE FROM message_translations WHERE idx in ({0})",
        String.Join(",", repliesIdsToDelete)
    )
);

I'm not an expert in EntityFramework, but I think when you use context.Database.ExecuteSqlCommand(command, str) , str is used as a parameter, so your command becomes DELETE FROM message_translations WHERE idx in ('1, 2, 3, 4') (note single quotes, '1, 2, 3, 4' is actually a string on server side).

You could use table-valued parameters if your DB was SQL server, may be it's possible to pass array as a parameter into PostgreSQL, have to try later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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