I'm trying to call a stored procedure in Entity Framework 4 application and so far getting strange results. Stored procedure takes IN and OUT parameters, and returns resultset. I mapped stored procedure and created a complex type that represents a row in returned resultset. I call it
using (MyObjectContext ctx = new MyObjectContext())
{
ObjectParameter out1 = new ObjectParameter("out1", typeof(String));
ObjectParameter out2 = new ObjectParameter("out2", typeof(String));
var res = ctx.my_proc(1,2, out1,out2);
}
The problem is that unless I call res.ToList() (or enumerate through res, or call any methods that accesses underlying collection), values of out1 and out2 are null.
How do I fix it?
Thanks
You cannot fix it. It is a gotcha. Result set must be materialized or thrown away before output parameters are accessible because these output parameters are transferred in the last result set so internal data reader must first read the returning result set with main data and then access the next result set to read output parameters. Btw. it is the same if you use ADO.NET directly - that is not a feature of Entity framework itself but the way how SQL server returns output parameters and the way how DataReader consumes result sets in sequential order.
when u call procedure or query that returns a table of rows
EF does real execution when user calls ToList or enumerate the return value
Related
I need to return info from database with T-SQL and I'm using dapper.
I've written this code:
SELECT *
FROM UserActivetionCode UA
WHERE UA.Username=#Username
AND UA.ActivetionCode= #ActivetionCode
AND UA.ExpireTime > GETDATE()
and I'm using this code:
var find = await roleConnection.QueryFirstAsync(command, new {
#ActivetionCode = ActivetionCode,
#Username = Username });
but it shows me this error:
Sequence contains no elements
This error means that the query didn't return any results.
If you don't want to get it, use QueryFirstOrDefaultAsync.
This will result with default(T) (T being whatever datatype the query should return) if the query returned no rows.
However, QueryFirst implies a known order in the resultset, which your query does not provide (as it doesn't have an order by clause) and in any case, I suspect that the combination of Username and ActivetionCode should probably be unique. In that case, I would go with QuerySingleOrDefault, which will throw an exception if the query returned more than one result.
I want to call a stored procedure in bulk with Dapper. Each call will return a different set of results, so I was using QueryMultiple. If I create the parameters like this:
var parameters = new DynamicParameters();
// The stored proc accepts a single integer, but I want to pass multiple so each call had a new value.
parameters.Add("LookupID", lookupIds);
var resultSet = connection.QueryMultiple("SPName", parameters, commandType: System.Data.CommandType.StoredProcedure);
I get an error that the stored procedure has too many arguments specified. So how else can I accomplish this?
QueryMultiple is about the results, not the inputs. To do what you want, you need to call the SP lots of times. Which you can do either via a simple foreach loop yourself, or many (not all) of the dapper methods will allow a convenience method by passing in an IEnumerable<T> as the outermost object, for example:
int[] ids = ...
var args = ids.Select(id => new { id, val = "ABC" });
db.Execute("whatever", args);
Which will execute the SQL once per item passing in #id and #val for each. In the case of the async API this can also be combined with MARS to remove the cost of latency between calls, but this is opt-in because MARS is not a default option.
Alternatively, you could write a new wrapper SP that takes a single parameter and splits it (the new string_split would be ideal), and do the loop at the server.
I have been reading on
https://github.com/ServiceStack/ServiceStack.OrmLite
to find methods so I can execute normal SQL (string commands), and get a result set back, but I dont think there is any.
I am testing OrmLite v 4.0.17.0.
On the page above, there is a method SqlList mentioned, but I have no such method available:
I have an ExecuteSql, but I get no result set back, just an int:
So, two questions:
Is there a way to execute custom queries, a method that takes in a string as parameter, and where I then get back a result set, rows or objects or something?
And while I am at it, how do I create a "LIMIT", for example "SELECT * FROM a LIMIT 10"?
Here is the version info:
Yeah I recently noticed that db.SqlList got lost in the OrmLite v4 refactor so I've restored it back in this commit. Which will be available in the next release of v4, before the end of the month.
You can still use db.Select for raw SELECT queries, e.g:
var results = db.Select<Poco>("SELECT * FROM a LIMIT 10");
It's only an issue when it's not a SELECT statement because we'd assume it's short-hand like:
var results = db.Select<Poco>("Foo = 'bar'");
And automatically add the rest of the SQL for you, but this is a problem when you're not issuing a SELECT statement, e.g. calling a stored procedure, which is what db.SqlList is for since the raw SQL remains untouched.
Support for LIMIT in Typed Expression API
Another way to query with a limit is to use the typed expression API, e.g:
var results = db.Select<Poco>(q => q.Limit(10));
How to handle stored procedure that returns different outputs in Entity Framwork.
For example , on sp, there is if condition and else condition. if condition return integer and else condition return datatable. How to handle this using entity framework in vs.
Please advice.
Starting from EF 4.1 this is possible.
The only requirement is to know what the SP is going to return in each case.
In my example I use
DbContext.Database.SqlQuery<TElement>(string sql, params object[] parameters)
This generic method takes as a generic parameter the type you would like to use for materialization. It also takes SQL expression you would like to execute as a parameter, along with it's parameters as param'd array.
Simplified SP (no input parameters) usage is:
var res = ctx.Database.SqlQuery<MyResultType1>("dbo.MyStoredProcedure");
foreach (var r in res)
{
System.Console.Out.WriteLine(
"col1:{0}; col2:{1}; col3={2}",
r.Col1,
r.Col2,
r.Col3);
}
So, you can do following:
IEnumerable res
if(...your logic...)
{
res = ctx.Database.SqlQuery<MyResultType1>(...your SP call...);
}
else
{
res = ctx.Database.SqlQuery<MyResultType2>(...your SP call...);
}
This way you are going to fill your collection with SP output resultset the way you want.
Click update model from database select your stored procedure and make sure it procedure has been added in Function Imports(Model Browser)
You can change return values from Edit function import window
and then just execute db.myProcedure();
eg:
just drag and drop your stored procedure and then
db.procedure(element1, element2);
db.SubmitChanges();
Ef4 does not support stored procedure with multiple returns of different types. We can do it either by direct calling of Sp via sql codes or can do the schema in linq.
Else we needs to use EF 4.1 and above.
I have a stored procedure GetTopRecords(). The sp returns the top 500 records.
I dragged the sp from the server explorer to the LinqtoSql designer surface.
I changed the return type to Record
In code I have:
var x = myDataContext.GetTopRecords();
var y = x.Count();
var z = x.ToList();
either one of the last two lines above throws an InvalidCastException
the type of x is
System.Data.Linq.SqlClient.SqlProvider.SingleResult<Record>
Why am I getting an exception? What am I doing wrong? Please help.
x is not a list, it is single element. As a single element you can't convert it to a list of more than one element or count how many elements it has.
As you say "I changed the return type to Record". Why did you do this?
Since this is L2S (Linq To SQL), I'm assuming it's using Lazy loading, which means that only when calling Count or ToList, which are of immediate execution, the query is performed.
That said, the problem should be related to what you are returning from the GetTopRecords method, which isn't compatible with the Record type.
You should use the L2S designer to check if the result of that method is correctly mapped to a Record data type. Meaning that Record should be a L2S mapped table and GetTopRecords should return data from that table.
Well,can you give details what GetTopRecords() .What it returns?do you need count of top records?
var x = i.ToList();
var y = x.Count();
then it will allowed,but when ever you use tolist() ToList iterates on the query and creates an instance of List<> initialized with all the results of the query.
which is same for count(),becuse count also need all records to perform counting.
the purpose of tolist is to prefilled data with result.
I think there there have been changes to the database schema since the linq to sql classes were generated. therefore there is a mismatch between the database table and the linq to Sql object representing it. therefore, the calls fail because the .NET cannot successfully cast from the db created object to the linq to sql object
I am not sure how I resolved this. But it is fixed now. If someone runs into this problem, please add a note here and I will look up my code and post the proper answer. While I thank the responders above, unfortunately, none of the answers above helped.