This thread gives a number of ways to provide a parameter to a stored procedure.
None of them are working for me.
This works:
this.PayrollContext.Database.SqlQuery<CSRRateEntity>("ord_getCSRRate #csr_num = '4745', #ord_pay_period_id = 784").ToList();
This does not:
return this.PayrollContext.Database.SqlQuery<CSRRateEntity>("Exec ord_getCSRRate #csr_num, #ord_pay_period_id",
new SqlParameter("csr_num", "4745"),
new SqlParameter("ord_pay_period_id", 784)
).ToList();
The Error message is that parameter is not supplied.
Have tried all the variations I can think of and still get that same error message.
This is using Code First, so no import is required. The SP is found, it is just missing the parameters.
Did you import the stored procedure into the edmx?
In the implementation that we have for the stored procedure it creates parameters like this:
var inputIdParameter = inputId.HasValue ?
new ObjectParameter("InputId", inputId) :
new ObjectParameter("InputId", typeof(int));
The result of the stored procedure function is given like this
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<T>("[SP_NAME]", inputIdParameter);
The solution turned out to be to change the order of the parameters in the stored procedure so that optional parameters come after the required parameters (like in c#).
Works:
ALTER procedure [dbo].[ord_GetCSRRate]#ord_pay_period_id int,#csr_num varchar(10) = null, #csr_id int = null, #update_csr_pay_flag bit = 0
Does not work:
ALTER procedure [dbo].[ord_GetCSRRate]#csr_num varchar(10) = null, #ord_pay_period_id int, #csr_id int = null, #update_csr_pay_flag bit = 0, #recursion_flag bit = 0
Related
The idea is I want to update the status and returning the id only if the status is different.
So, I have a prepared statement like this:
var theQuery = `UPDATE process SET status=$1 WHERE status!=$1 AND id=$2 RETURNING id`
Then, I called it with this:
err = statement.QueryRow("set", 12).Scan(&id)
Then there is an error appear like this.
runtime error: invalid memory address or nil pointer dereference
When I tried:
var theQuery = `UPDATE process SET status='$1' WHERE status!='$1' AND id=$2 RETURNING id`
It runs. Then, when I run it again, I am expecting to get no rows, but it still returning the id. It looked like it still updating the rows and ignored the status!='$1' part.
Thank you
So, I just find the solution. Instead of using $1 twice, the prepared statement will received 3 arguments:
var theQuery = `UPDATE process SET status=$1 WHERE status!=$2 AND id=$3 RETURNING id`
Then, I call the prepared statement like this.
status := "set"
err = statement.QueryRow(status, status, 12).Scan(&id)
I know maybe this is not the best approach to solve the problem. But it worked for me.
I found the following comment on the Dapper .NET project home page.
Dapper supports varchar params, if you are executing a where clause on a varchar column using a param be sure to pass it in this way:
Query<Thing>("select * from Thing where Name = #Name", new {Name =
new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = true });
On Sql Server it is crucial to use the unicode when querying unicode and ansi when querying non unicode
I'm evaluating Dapper for use with a legacy database (SQL Server 2008), with lots of stored procedures with varchar parameters, and I'm a little confused by this restriction.
With hand-crafted ADO.NET code, I'd use the following for the above query:
new SqlParameter("#Name", "abcde")
without specifying whether it's unicode or not, nor the length.
Why do I need this verbose DbString syntax with Dapper, specifying the column length, IsFixedLength and IsAnsi?
Why IsFixedLength = true for a varchar column (I'd expect it to be true for a char or nchar column)?
Do I have to use DbString like this for stored procedure parameters?
I was expecting Dapper to make my DAL code more concise, but this seems to be making it more verbose for varchar parameters.
UPDATE
I've researched a bit further, to try to understand why Dapper would have this varchar restriction, which I don't appear to have in my hand-crafted code, where I would normally create an input parameter as follows:
var parameter = factory.CreateParameter(); // Factory is a DbProviderFactory
parameter.Name = ...;
parameter.Value = ...;
and usually leave the provider to infer the DbType using its own rules, unless I specifically want to coerce it.
Looking at Dapper's DynamicParameters class, it has a method AddParameters which creates parameters as follows:
var dbType = param.DbType; // Get dbType and value
var val = param.Value; // from
...
// Coerce dbType to a non-null value if val is not null !!!!!
if (dbType == null && val != null) dbType = SqlMapper.LookupDbType(val.GetType(),name);
...
var p = command.CreateParameter();
...
if (dbType != null)
{
p.DbType = dbType.Value;
}
I.e. it explicitly coerces IDataParameter.DbType to a value it looks up with its own algorithm, rather than leaving the provider to use its own rules.
Is there a good reason for this? It seems wrong for me, particularly in the light of the comment about Dapper's support for varchar parameters.
You need this syntax when working with ODBC.
You would need to define a CHAR(30) field as a DbString in c# for Dapper and also set the length (30) and ansi (true) values to prevent Dapper from assuming the string was a text/blob type. Otherwise you will likely receive the error: "Illegal attempt to convert Text/Byte blob type".
I was getting this error using ODBC to connect to Informix until I defined my param as a DbString() and set the length and ansi values.
More info here.
var param = new { Varchar1 = "", Varchar2 = "" };
db.Query("SP", param, commandType:CommandType.StoredProcedure);
For while I am trying to call SQL Server 2008 R2 stored procedure using PetaPoco.
My stored procedure accepts a table valued parameter.
How I can call the stored procedure in petapoco with table value param?
Here what I am trying to do:
var db = new PetaPoco.Database("repikaciskaBaza");
DataTable table = new DataTable();
DataColumn id = table.Columns.Add("id", type: typeof(Int32));
for (int i = 0; i < 10;i++ )
{
DataRow row = table.NewRow();
row["id"] = i;
table.Rows.Add(row);
}
var param = new SqlParameter();
param.DbType = DbType.Object;
param.ParameterName = "#art_id";
param.SqlValue = table;
var lista = db.Query<pocoArts>(";exec dbo.test_sporc_param #0", param);
This code gives me an exception :
The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect.
Parameter 3 ("#0"): Data type 0x62 (sql_variant) has an invalid type for type-specific metadata.
If I set parametar ty value
param.SqlDbType = SqlDbType.Structured;
Then I get exception like
The table type parameter '#0' must have a valid type name.
When I define my param like
param.SqlDbType = SqlDbType.Structured;
param.SqlValue = table;
param.ParameterName = "#art_id";
param.TypeName = SqlDbType.Structured.ToString();
Then I get exception
Column, parameter, or variable #0. : Cannot find data type Structured.
How I can define SqlParam with table valued param so I can send it whit data to SQL Server?
Solution:
var param = new SqlParameter();
param.SqlDbType = SqlDbType.Structured; // According to marc_s
param.SqlValue = table;
param.ParameterName = "#art_id";
param.TypeName = "dbo.typ_art_id"; // this is TYP from SQL Server database it needs to be equal to type defined in SQL Server not type of param
According to the relevant MSDN documentation on table-valued parameter, you should use:
var param = new SqlParameter();
param.SqlDbType = SqlDbType.Structured;
The SqlDbType.Structured is the key to this. Don't use DbType.Object.
I have simple stored procedure, that takes couple parameters and updates table.
How to pass parameters via BDC?
For example, to execute stored procedure, that selects rows and takes one param, code below.
BdcService bdcservice = SPFarm.Local.Services.GetValue<BdcService>();
IMetadataCatalog catalog = bdcservice.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current);
// entity.GetLobSystem().GetLobSystemInstances()[0].Value;
IEntity entity = catalog.GetEntity(Utils.EntityNamespace, "GetMessage");
ILobSystemInstance lobSystemInstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value;
IFilterCollection filters = entity.GetDefaultFinderFilters();
ComparisonFilter filter = (ComparisonFilter)filters[0];
filter.Value = code;
IEntityInstanceEnumerator enumerator = entity.FindFiltered(filters, lobSystemInstance);
DataTable result = entity.Catalog.Helper.CreateDataTable(enumerator);
DataTable result contains selected rows.
But how to pass couple parameters to Update procedure?
BdcService bdcservice = SPFarm.Local.Services.GetValue<BdcService>();
IMetadataCatalog catalog = bdcservice.GetDatabaseBackedMetadataCatalog(SPServiceContext.Current);
// entity.GetLobSystem().GetLobSystemInstances()[0].Value;
IEntity entity = catalog.GetEntity(Utils.EntityNamespace, "ContractAdd");
ILobSystemInstance lobSystemInstance = entity.GetLobSystem().GetLobSystemInstances()[0].Value;
// entity.ExecuteScalar();
entity has method "ExecuteScalar", but how to pass params via this method?
I have a list AllIDs:
List<IAddress> AllIDs = new List<IAddress>();
I want to do substring operation on a member field AddressId based on a character "_".
I am using below LINQ query but getting compilation error:
AllIDs= AllIDs.Where(s => s.AddressId.Length >= s.AddressId.IndexOf("_"))
.Select(s => s.AddressId.Substring(s.AddressId.IndexOf("_")))
.ToList();
Error:
Cannot implicitly convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<MyCompany.Common.Users.IAddress>'
AllIDs is a list of IAddress but you are selecting a string. The compiler is complaining it cannot convert a List<string> to a List<IAddress>. Did you mean the following instead?
var substrings = AllIDs.Where(...).Select(...).ToList();
If you want to put them back into Address objects (assuming you have an Address class in addition to your IAddress interface), you can do something like this (assuming the constructor for Address is in place):
AllIDs = AllIDs.Where(...).Select(new Address(s.AddressID.Substring(s.AddressID.IndexOf("_")))).ToList();
You should also look at using query syntax for LINQ instead of method syntax, it can clean up and improve the readability of a lot of queries like this. Your original (unmodified) query is roughly equivalent to this:
var substrings = from a in AllIDs
let id = a.AddressId
let idx = id.IndexOf("_")
where id.Length >= idx
select id.Substring(idx);
Though this is really just a style thing, and this compiles to the same thing as the original. One slight difference is that you only have to call String.IndexOf() one per entry, instead of twice per entry. let is your friend.
Maybe this?
var boundable =
from s id in AllIDs
where s.AddressId.Length >= s.AddressId.IndexOf("_")
select new { AddressId = s.AddressId.Substring(s.AddressId.IndexOf("_")) };
boundable = boundable.ToList();