4

Situation

I have many parameterized SQL commands. I execute these commands one after the other in a loop and looks like this:

public void SaveChanges()
{
    using (var ts = _Context.Database.BeginTransaction())
    {
        try
        {
            _Context.SaveChanges();

            foreach (var cmd in _Commands)
            {
                if (cmd.Parameter != null)
                {
                    _Context.Database.ExecuteSqlCommand(cmd.Sql, cmd.Parameter.ToArray()); 
                }
            }

            ts.Commit();
        }
        catch (Exception ex)
        {
            ts.Rollback();
            throw new Exception("SaveChanges");
        }
    }
}

The above code works, also transcaction rollback works as expected.

My command class looks like this:

public class SqlBuilderCommand
{
    public string Sql { get; set; }

    public List<SqlParameter>  Parameter {get;set;}
}

Possible duplicates without concrete solution

I have figured out several, possible duplicates to this question. The closest one is this:

Possible Duplicate 1

Unfortunately, it doesn't help me with the Entity Framework (or I just don't get it)

Questions

  1. Is it possible to execute all the commands in the list in one round trip?

  2. If not, is it possible with ADO.NET?

SOLUTION AND DRAWBACKS / LIMITATIONS

Thanks to @Evgeni for the right answer.Yes, you can concatenate many SQL-Strings and just send the parameter as a list in one round trip. That's great.

But there is a limitation with SQL-Server. SQL-Server only accepts a maximum of 2100 parameters with one command. So if you have an object with 7 database columns, the maximum bulk insert is 300 objects per command. Otherwise you get an exception.

If I do that for 5000 objects, it leads to 17 bulk inserts (5000/300). I stopped the time for 5000 objects and it is still 8-9 seconds, which is way too slow, because I know, that raw SQL will do it much, much faster.

At this point, I think there is no way around raw SQL for me, unless someone could tell me, that there is a way to speed up sql commands.

Maybe I will write a follow up question to this. Damn.

Community
  • 1
  • 1
Michael
  • 938
  • 1
  • 10
  • 34

1 Answers1

7

Technically you can execute multiple commands in one go:

    var n1 = new SqlParameter("@name1", System.Data.SqlDbType.VarChar);
    n1.Value = "name 1 ";
    var u1 = new SqlParameter("@uid1", System.Data.SqlDbType.UniqueIdentifier);
    u1.Value = Guid.Parse("guid here");
    var n2 = new SqlParameter("@name2", System.Data.SqlDbType.VarChar);
    n2.Value = "name2";
    var u2 = new SqlParameter("@uid2", System.Data.SqlDbType.UniqueIdentifier);
    u2.Value = Guid.Parse("guid here");
    var sqlParams = new[]
    {
        n1, n2, u1, u2
    };

    using (var db = new DbContext("default"))
    {

        db.Database.ExecuteSqlCommand(@"
            Update property set name = @name1 where uid = @uid1; 
            Update property set name = @name2 where uid = @uid2;", sqlParams);
    }

So I'd imagine if you concatenate your sql, it should just work.

Evgeni
  • 3,341
  • 7
  • 37
  • 64
  • 1
    You can totally replace strings with sql parameters. I'll update code... – Evgeni Feb 21 '17 at 17:26
  • 1
    Aaaaahhh, NOW I get, what you tried to explain to me. I will evaluate this solution at the end of the week, because I have no time today and tomorrow. It looks very promising from here. If it fits, I will mark your answer as valid and post my solution in the question. Thank you Evgeni! – Michael Feb 21 '17 at 18:10
  • 1
    This is the right answer. The only problem I have right now, that the maximum number of paramters for SQL-Server is 2100 per command. So if you have an object with 7 database columns, you could send max 300 with one command. For 5000 inserts, I stopped a time of 8 seconds which is still to slow in my opinion. I think there is no way around raw SQL. I had a look in3rd party libraries, which can handle bulk inserts for EF and they also produce raw SQL. Anyway - your answer was absoluteley correct. Thanks for your help! – Michael Mar 03 '17 at 04:12
  • 1
    I also wrote the solution and limitation in the question. – Michael Mar 03 '17 at 04:28