Entity Framework Stored Procedure with Multiple Record Set not accepting my parameter - entity-framework

I'm using Microsofts suggested solution for using Entity Framework to read multiple record sets from a stored procedure but added a small snippet to use parameters and it's not working. I've had a co-worker look at the code and tell me it looks like it should work so I thought I'd ask here.
Using the 4.5 framework is not an option. I'm stuck with 4.0 and etity framework 4.4.
App MyApp = (App)Application.Current;
EnterpriseEntities EE = new EnterpriseEntities();
EE.Database.Connection.ConnectionString = MyApp.EnterpriseEntityConnectionString;
var cmd = EE.Database.Connection.CreateCommand();
cmd.CommandText = "[dbo].[spSelectWaterUsesByRightID]";
var param = cmd.CreateParameter();
param.Direction = ParameterDirection.Input;
param.DbType = DbType.Int32;
param.ParameterName = "#RightID";
param.Value = this.RightID;
cmd.Parameters.Add(param);
EE.Database.Connection.Open();
var reader = cmd.ExecuteReader();
List<WaterUses> ListOfWaterUses = (((System.Data.Entity.Infrastructure.IObjectContextAdapter)EE)
.ObjectContext
.Translate<WaterUses>(reader, "WaterUses",System.Data.Objects.MergeOption.AppendOnly)).ToList();
When I get to the ExecuteReader line I get an error message that the stored procedure requires Parameter #RightID but that's what I'm passing. I checked the parameter count right before it executes and it's at 1.

You have to add
cmd.CommandType = CommandType.StoredProcedure;
somewhere before cmd.ExecuteReader().

Related

Getting error 'Insight.Database.FastExpando' does not contain a definition for 'Set1'

The following code is giving the above error, and I cannot figure out why:
var x = _sqlConn.Connection().QueryResults<Results>("MyDb.dbo.get_records", new { id = theId });
int retVal = x.Outputs.Return_Value;
if (retVal == 0) // ...meaning result set was also returned...fine to this point.
{
var list = x.Outputs.Set1; // exception thrown here with above error
var temp = list.FirstOrDefault();
I have been using other features of Insight.Database for a number of years, but have not had to retrieve a SQL RETURN value at the same time as a recordset. The SQL itself works correctly in SSMS, returning a result set and the RETURN value of 0, as expected. This is happening in VS2019, .NET 4 and .NET 4.5.2; Insight.Database 5.2.7 and 5.2.8.
I got this code from the following page:
https://github.com/jonwagner/Insight.Database/wiki/Specifying-Result-Structures
where it shows this:
var results = connection.QueryResults<Beer, Glass>("GetAllBeersAndAllGlasses");
IList<Beer> beers = results.Set1;
which I combined with the following code from here:
https://github.com/jonwagner/Insight.Database/wiki/Output-Parameters
var results = connection.QueryResults<Results>("MyProc", inputParameters);
var p = results.Outputs.p;
That part works. It's accessing .Set1 that is failing, and I am not sure how to track down why.
I do not have experience with the FastExpando class, but Jon promised magic, and I want to believe. Thanks for any help.
I haven’t tried results+dynamic objects in a while…
I think it is because you are doing:
QueryResults<Results> and Results is an Insight type
You probably want:
QueryResults<MyType>
And then you get back a Results<MyType>
Which contains the return val and Set1
If not, post a ticket over on github and we will help you out.

Entity Framework Core, Stored Procedure

I am totally confused regarding how to use Stored Procedures using Entity Framework Core. If the stored procedure return an anonymous type, how do I retrieve the data? If the return type is not anonymous, what should I do? How do I add input/output parameters?
I am asking these questions because everywhere I look, I get a different answer. I guess EF Core is evolving rapidly and Microsoft is dabbling with a lot of ideas.
How do I add input/output parameters?
I'm going to answer this particular question of yours.
Below is a TSQL stored procedure with two input and two output parameters
CREATE PROCEDURE [dbo].[yourstoredprocedure]
-- Add the parameters for the stored procedure here
#varone bigint
,#vartwo Date
,#varthree double precision OUTPUT
,#varfour bigint OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- YOUR CODE HERE
SET #varthree = 10.02;
SET #varfour = #varone;
return;
END
Now To execute this stored procedure using Entity Framework Core
MyContext.Database
.ExecuteSqlCommand(#"EXECUTE [yourstoredprocedure] " +
" {0} " +
", {1} " +
",#varthree OUTPUT " +
", #varfour OUTPUT ", dataOne, dataTwo, outputVarOne, outputVarTwo);
var outputResultOne= outputVarOne.Value as double?;
var outputResultTwo= outputVarTwo.Value as long?;
You can pass your input simply using parameterized query as above. You can also create named parameters. such as for output parameters, I've created two named parameters as -
var outputVarOne = new SqlParameter
{
ParameterName = "#varthree ",
DbType = System.Data.DbType.Double,
Direction = System.Data.ParameterDirection.Output
};
var outputVarTwo = new SqlParameter
{
ParameterName = "#varfour ",
DbType = System.Data.DbType.Int64,
Direction = System.Data.ParameterDirection.Output
};
And This is how using EF Core you execute a stored procedure with input and output parameters. Hope this helps someone.
This solution provides methods that call a stored procedure and maps the returned value to a defined (non-model) entity. https://github.com/verdie-g/StoredProcedureDotNetCore
Microsoft address this issue:
"SQL queries can only be used to return entity types that are part of your model. There is an enhancement on our backlog to enable returning ad-hoc types from raw SQL queries." https://learn.microsoft.com/en-us/ef/core/querying/raw-sql
And here is the issue tracked in GitHub: https://github.com/aspnet/EntityFramework/issues/1862
you might use an extention like StoredProcedureEFCore
Then the usage is more intuitively.
List rows = null;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 300L)
.AddParam("limitOut", out IOutParam<long> limitOut)
.Exec(r => rows = r.ToList<Model>());
long limitOutValue = limitOut.Value;
ctx.LoadStoredProc("dbo.ReturnBoolean")
.AddParam("boolean_to_return", true)
.ReturnValue(out IOutParam<bool> retParam)
.ExecNonQuery();
bool b = retParam.Value;
ctx.LoadStoredProc("dbo.ListAll")
.AddParam("limit", 1L)
.ExecScalar(out long l);

EF6 code-first: access to database before update database

I'm trying to create a project with EF6.1 with code-first. All works fine I have migration is enabled, create and update DB works too. Now my Problem:
I have create a table "VersionHistory" and a CompanyInfo table.
I'm writing an "Upgrade Wizzard" for update the database. Is it possible to get data from this tables to Display Information (e.g. YourCompanyName and Update from Program Version 1.x to 1.y) before I start the database update?
Should I use classic SQLConnection for this?
Many thanks
You can use a SQL Connection (it can be the same of EF) or you can disable EF database structure checking.
System.Data.Entity.Database.SetInitializer<MyModel>(null);
EDIT
If you access to an entity that is not updated on the database, you can receive Ado exceptions from EF (i.e. missing columns, missing tables and so on).
In compliance with "bubi" I will use a SQLConnection based on my Context e.g.
using (var ctx = new AppContext()) {
ctx.Database.Connection.Open();
var cmd = ctx.Database.Connection.CreateCommand();
cmd.CommandText = "Select * From CompanyInfo";
var rdr = cmd.ExecuteReader();
var infos = (from row in rdr.Cast<System.Data.Common.DbDataRecord>()
let entityId = (int)row["EntityId"] //internal key
let entityKey = (string)row["EntityKey"] //visible key
let displayname = (string)row["DisplayName"] //company name
// some more stuff (version, etc.)
select new NOCompanyInfo {
EntityId = entityId,
EntityKey = entityKey,
DisplayName = displayname,
DBName = dbName,
...
}).ToList();
return new ObservableCollection<NOCompanyInfo>(infos);
}
Thanks

Getting "The SqlParameter is already contained by another SqlParameterCollection." error while using SqlQuery command

I am trying to parameterize a dynamic query and run it using SqlQuery method in Entity Framework code first.
The first time I execute SqlQuery it works as expected so I am sure there is nothing wrong with query or parameters but immediately I execute the same command with the same parameters second time and I get this error
"The SqlParameter is already contained by another SqlParameterCollection."
Since I am already using ToList() method here, I have no idea what the cause could be!
Here is the simulated code.
using (var context = Common.GetDbContext())
{
var parameters = new List<SqlParameter>();
//populating parameters here...
var sqlQuery = "Select * from MyTable where UserId=#p1 and And Active=#p2";
// first time
var result = context.Database.SqlQuery<ResultType>(sqlQuery, parameters.ToArray()).ToList();
//second time
result = context.Database.SqlQuery<ResultType>(sqlQuery, parameters.ToArray()).ToList();
}
Any idea?
Hi SqlParameter is clonable. Try this:
result = context.Database.SqlQuery<ResultType>(sqlQuery, parameters.Select(x => x.Clone()).ToArray()).ToList();
See https://msdn.microsoft.com/en-us/library/vstudio/bb338957%28v=vs.100%29.aspx

Cannot create parameterised query for Interbase using ADO.NET

I'm trying to issue a parameterised SELECT to an Interbase XE database using ADO.NET. The code I'm using is as follows:
using (OdbcConnection odbcConnection = new OdbcConnection(ConfigurationManager.ConnectionStrings["LawbaseTest"].ToString()))
{
odbcConnection.Open();
using (OdbcCommand odbcCommand = new OdbcCommand())
{
odbcCommand.CommandType = CommandType.Text;
odbcCommand.Connection = odbcConnection;
odbcCommand.Parameters.Add(new OdbcParameter(":CaseNumber", 1265));
odbcCommand.CommandText = "select * from cmstub where cm_recnum = :CaseNumber";
using (IDataReader rdrData = odbcCommand.ExecuteReader())
{
Output(rdrData["CM_DESC"]);
}
}
}
I'm getting the following error:
ERROR [42S22] [DataDirect][ODBC InterBase driver][InterBase]Dynamic SQL Error, SQL error code = -206, Column unknown, CASENUMBER
Which suggests to me that the query is not being sent to Interbase in a syntax it recognises as a parameterised query.
This is rather harder than I was expecting. Am I being a ficko? Can you help?
It seems to be the norm that named parameters aren't supported widely, did you try using ? instead, i.e. cm_recnum = :CaseNumber to cm_recnum = ?