I noticed this bug the other day, and reconfirmed it today. Also found others having this issue.
Entity Framework will return no results (when it ought to) and will not throw an exception in the following scenario:
- Execute a stored proc using the SqlQuery method
- Provide at least one optional parameter
- Skip at least one optional parameter
By "Skip" I'm referring to the order of the parameters in the proc's signature. As long as you don't skip any optional parameters there is no problem; it's only when you've provided an optional parameter that comes after another one that you didn't include.
There could be other variants. For example, I suspect the same issue would occur if you provide a required parameter that comes after an optional parameter that you've skipped... not sure about that though.
Now consider this scenario:
I add a new optional parameter to the end of a proc's signature. Now I go to update a SqlQuery() call and add the new parameter but b/c of aforementioned bug I get no results. I have two options: 1) I can add all the optional parameters that I had left out. Or 2) I can move the new parameter to be further to the left in the signature so that I'm no longer skipping any parameters in my SqlQuery() call.
The problem with 2), of course, is that this could break existing code that is now skipping that parameter. So, really, my only option seems to be to just include all parameters all the time which totally defeats the entire purpose of having optional parameters in the first place.
Is there any way to remedy this or am I just stuck having to always pass in all parameters if I use Entity Framework to call stored procs?
EDIT: Another potential problem I see with this is that it disallows me from letting SQL use a default value because there is no 'value' you can pass to SQL to tell it to use the default. You tell it to use the default by NOT passing a value... which EF doesn't not seem to handle properly.
EDIT 2:
Minimal reproducable code:
CREATE PROC MyProc @p1 int, @p2 int = 0, @p3 int = 0
as
select * from MyTable
where p1 = @p1
and (@p2 = 0 or p2 = @p2)
and (@p3 = 0 or p3 = @p3)
C# Code:
List<MyObject> SomeMethod(int p1, int p3)
{
return db.Database.SqlQuery<MyObject>("dbo.MyProc @p1, @p3",
new SqlParameter("@p1", p1),
new SqlParameter("@p3", p3)
).ToList();
}