Question

I'm using ExecuteStoreCommand to facilitate bulk deletes.

This Works

// ExecuteStoreCommand syntax via http://stackoverflow.com/a/13024320/740639
// Delete all of today's events
DateTime eventDate = DateTime.Now;

string sql = "DELETE FROM EventCalendar WHERE EventDate = {0}";
context.ObjectContext.ExecuteStoreCommand(sql, new object[] { eventDate });

I want to do this, but it does not work

I get an ArgumentException: "No mapping exists from object type System.DateTime[] to a known managed provider native type."

// Delete all of the events for the past 3 days
DateTime[] eventDates = new DateTime[] {
   DateTime.Now.AddDay(-1),
   DateTime.Now.AddDay(-2),
   DateTime.Now.AddDay(-3)
};

string sql = "DELETE FROM EventCalendar WHERE EventDate IN ({0})";
context.ObjectContext.ExecuteStoreCommand(sql, new object[] { eventDates });

Proposed Solution

I could convert my DateTime[] into the string "'2013-06-24', '2013-06-23', '2013-06-22'" and pass that as the parameter, but that seems like a hack.

I know there are libraries that add bulk delete support to EF, but I don't want to go that route at this time.

Any suggestions?

Was it helpful?

Solution

If you manipulate the string, every time you change the dates you will get a slightly different SQL statement. It may look the same, but the string is different and will have a different hash. So this subverts caching of the execution plan and kills performance.

You can't really pass parameters in an IN clause the way you're thinking. There are some other ideas in this post that might work, but if you read the notes they all say they have lousy performance.

If you can be assured that you will have a fixed number of inputs, you could use the technique of passing them as separate parameters:

... WHERE EventDate IN (@dt1, @dt2, @dt3)

Otherwise, I would go with an approach like Tom suggested, pass them as a delimited string and parse it on the server.

Also - since you are doing an exact match, you probably want to snap to midnight using DateTime.Today rather than DateTime.Now, or use the .Date property of an existing DateTime.

Here's another suggestion, if you really are just trying to delete for the last three days, why not do this?

string sql = "DELETE FROM EventCalendar WHERE EventDate BETWEEN {0} AND {1}";
context.ObjectContext.ExecuteStoreCommand(sql,
    new object[] { DateTime.Today.AddDays(-3), DateTime.Today.AddDays(-1) });

Or with a bit of thought, you could probably just use sql getdate() and similar functions instead of passing parameters at all.

OTHER TIPS

You could combine the dates with a delimiter on the .net side, pass it through as a paramter, and then use a Table-Valued function to split a delimited string on the server side.

Pass in something like "2013-06-24|2013-06-23|2013-06-22"

http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top