EF generates wrong query, causing exception: Must declare the scalar variable '#...' - c#

I am using Entity Framework 4.3, and below is my code (BTW, the RealPrice field of the gift table is of decimal type):
var filters = new StringBuilder();
var parameters = new List<object>();
decimal numRealPrice = 25.00m;
filters.Append("RealPrice = #RealPrice");
var paramRealPrice = new SqlParameter("#RealPrice", SqlDbType.Decimal);
paramRealPrice.Value = numRealPrice;
parameters.Add(numRealPrice);
string sqlStatement = "SELECT * FROM gift WHERE ";
sqlStatement = sqlStatement + filters;
List<OM_Gift_BO> gifts = this.objEntity.ExecuteStoreQuery<OM_Gift_BO>(sqlStatement, parameters.ToArray()).ToList();
//....
And the framework somewhat generated a SQL query(according to Express profiler 2.0):
exec sp_executesql N'SELECT * FROM gift WHERE RealPrice = #RealPrice',N'#p0 decimal(4,2)',#p0=25.00
go
I have no idea where does the name 'p0' come from, however, since it is different from RealPrice, I got an exception saying:
Must declare the scalar variable "#RealPrice".
Well, this method works OK with string type parameters.
Any help is appreciated, thanks in advance.

The problem seems to be your assigning numRealPrice directly to your parameters and passing that directly to ExecuteStoreQuery
Replace
parameters.Add(numRealPrice);
With
parameters.Add(paramRealPrice);
Additionally I'm not sure if its of any value, as it depends on what your trying to achieve, however you could probably shorten your code as follows
var statement = "SELECT * FROM gift WHERE RealPrice = {0}";
var gifts = context.ExecuteStoreQuery<OM_Gift_BO>(statment, numRealPrice).ToList();

Related

Conversion failed when converting from string to uniqueidentifier - loading DataTable with ExecuteReader

In attempting to do a SQL query (which returns one string and one uniqueidentifier to columns 0 and 1 respectively) I get "Conversion failed when converting from a character string to uniqueidentifier" in my exceptions log. How can I avoid this? I'm assuming the issue is, the datatables columns are not defined, so it's expecting a string and SQL is trying to convert it. The exception is logged. Surprisingly to me the GUID is stored successfully to da[1]. So my program technically works, however I want to clear this exception and to do that I need to understand why it's happening and how to go about fixing it.
da = new DataTable();
da.Clear();
...
string invoiceStatusSQL = #"select status,invoice_id from invoices where acct_id='" + accountid + "'";
command = new SqlCommand(invoiceStatusSQL, cnn);
da.Load(command.ExecuteReader());
You should always parameterise your SQL queries to help prevent SQL injection and avoid problems like you're facing now. See Why do we always prefer using parameters in SQL statements?.
Use SqlParameter to add the parameters to the SqlCommand.
string invoiceStatusSQL = #"select status, invoice_id from invoices where acct_id = #accountId";
command = new SqlCommand(invoiceStatusSQL, cnn);
SqlParameter idParam = new SqlParameter("#accountId", accountid);
command.Parameters.Add(idParam);
da.Load(command.ExecuteReader());
You can also specify the actual database type when creating the parameter, which will reduce any issues you might have with the framework inferring the type incorrectly (although I don't think that would happen in your case for a Guid/UniqueIdentifier). One way to specify the type is shown below.
var p = new SqlParameter
{
ParameterName = "#accountId",
SqlDbType = SqlDbType.UniqueIdentifier,
Value = accountid
};

SQL Syntax in C#

I'm trying to understand why in C# if you have a sql string why you would have to put tick (') marks in the following where clause in order for this to work. Could someone please explain the reasoning behind this?
where ProgramServer='" + machineName.ToString() + "' and Active=1;
You can avoid those tick (') marks and use Parameters, They will also save you from SQL Injection.
The reason you see those ticks are because SQL expects string type values to be enclosed in single ticks.
What you're seeing is a dynamically built SQL query in the code. When querying based on a string value, the string must be wrapped in single quotes. The final SQL string would look something like:
select * from someTable where ProgramServer = 'YourMachineName' and Active = 1;
Unfortunately, that is far from the best way to do things. You should be using parameterized queries instead:
var query = "select * from someTable where ProgramServer = #machineName and Active = 1;";
using(var conn = new SqlConnection(connString))
{
var command = new SqlCommand(query, conn);
command.Parameters.Add("machineName", machineName.ToString());
// Execute and get the results
}

the equivalent of a sql procedure in access query

i have a sql procedure, but as access accepts only single statement, i'd like to control the differents statement through the code side using C# with Dbcommand...in order to find the equivalent. here is the sql procedure, i'm gonna show you the C# code but i got an error.
CREATE PROCEDURE CreateOrders
(#cartId char(36))
As
/*insert a new record into Commande étape 1 :"PasserCommande1"*/
DECLARE #CmdID int
INSERT INTO Commande DEFAULT VALUES
/*save the new commande id*/
SET #CmdID = ##IDENTITY
/*Add the order detail to DetailsCommande(orderdetails table) étape 2 :"PasserCommande2"*/
INSERT INTO DetailsCommande ( CmdID, ProduitID, ProduitTitre, Quantite, CoutUnitaire )
SELECT [#CmdID], livres.NumLivre, livres.titre, ShoppingCart.Quantite, livres.prix
FROM livres INNER JOIN ShoppingCart ON livres.NumLivre = ShoppingCart.ProduitID
WHERE ShoppingCart.CartID=[#CartID]
/*Clear the shopping Cart étape 3 :"PasserCommande3"*/
DELETE FROM ShoppingCart
WHERE CartID = #CartID
/*return the order id étape 4:"PasserCommande4"*/
SELECT #CmdID;
so i separated the procedure in 4 differents statements, so that i can call them one by one with c#, but i got a error when retreiving the ##identity value from the Commande table to put it in the DetailsCommande. the CmdID has an identity property in the table Commande. here is what i'm trying to do in C#:
public static string PasserCommande()
{
//étape 1
//on obtient l'objet configuré DbCommande
DbCommand m_cmd = LibAccesGenerique.CreerCmd();
//on définit la procédure stockée
m_cmd.CommandText = "PasserCommande_1";
LibAccesGenerique.ExecuteNonQuery(m_cmd);
//étape 2
DbCommand m_cmd1 = LibAccesGenerique.CreerCmd();
m_cmd1.CommandText = "PasserCommande_2";
//on crée un nouveau paramètre
DbParameter m_param = m_cmd1.CreateParameter();
m_param.ParameterName = "#CmdID";
m_param.Value = "##IDENTITY";
m_param.DbType = DbType.Int32;
m_cmd1.Parameters.Add(m_param);
//2ème param
m_param = m_cmd1.CreateParameter();
m_param.ParameterName = "#CartID";
m_param.Value = ShoppingCartId;
m_param.DbType = DbType.String;
m_param.Size = 36;
m_cmd1.Parameters.Add(m_param);
LibAccesGenerique.ExecuteNonQuery(m_cmd1);
//étape3
DbCommand m_cmd2 = LibAccesGenerique.CreerCmd();
m_cmd2.CommandText = "PasserCommande3";
DbParameter m_param2 = m_cmd2.CreateParameter();
m_param2 = m_cmd1.CreateParameter();
m_param2.ParameterName = "#CartID";
m_param2.Value = ShoppingCartId;
m_param2.DbType = DbType.String;
m_param2.Size = 36;
m_cmd2.Parameters.Add(m_param);
LibAccesGenerique.ExecuteNonQuery(m_cmd2);
//étape 4
DbCommand m_cmd3 = LibAccesGenerique.CreerCmd();
m_cmd3.CommandText = "PasserCommande_4";
//on créer un nouveau paramètre
DbParameter m_param1 = m_cmd3.CreateParameter();
m_param1.ParameterName = "#CmdID";
m_param1.Value = "##IDENTITY";
//m_param1.Direction = ParameterDirection.InputOutput;
m_param1.DbType = DbType.Int32;
m_cmd3.Parameters.Add(m_param1);
return LibAccesGenerique.ExecuteScalar(m_cmd3);
}
the error comes at etape 2 as i put in my comments. the exception says that the format of the input string is incorrect... i'm sure it comes when i try to assign the ##identity to #cmdID paramater. i don't know if there is a another way to code it.
##IDENTITY works with access, but it's a bit ordinary. Try sending it as a straight command
SELECT ##IDENTITY;
assigning the results to a variable using ExecuteScalar, then assigning that variable to the parameter instead. Also bear in mind that with access, ##IDENTITY only works with a normal AutoNumber, not a ReplicationID (GUID).
You should return ##Identity as an 'Output' parameter. Add an output parameter to your stored procedure and add a the same parameter to your C# code with Direction = ParameterDirection.Output.
See this answer for a great example: Using stored procedure output parameters in C#
Also, as a best practice, consider changing ##Identity to Scope_Identity().

What is wrong with my paramerized mysql statement in c#?

When I try to execute this, I get an exception saying the syntax is incorrect?
string sql= string.Format(#"SELECT valueA
FROM tableA
WHERE columnA = #columnValueA");
var parameters = new MySqlParameter[1];
parameters[0] = new MySqlParameter("#columnValueA", string.Format("{0}","abc"));
foreach (var mySqlParameter in parameters)
{
cmd.Parameters.AddWithValue(mySqlParameter.ParameterName, mySqlParameter.Value);
}
//later I execute, it tells me the syntax is incorrect
-- I am trying to execute something on the database similar to below
SELECT valueA
FROM tableA
WHERE columnA = "abc"
do you need # in the MySqlParameter string? I would imagine you could do without it?
My query is correct, essentially, what was happening nested deeply within the code was it was appending an extra ) which was rendering the query syntax incorrect.

What goes in the params parameter of the .SqlQuery() method in Entity Framework?

The method takes a string for the query, and an array of Object [] for the parameters, presumably to avoid SQL Injection.
However nowhere on earth is it documented what you should put into the object array.
There is another question on SO that asks this exact same thing, but the accepted answer doesn't work: When using DbSet<T>.SqlQuery(), how to use named parameters?
I've tried all forms of parameter replacement I can think of and all of them throw an exception. Any ideas?
Would that it were as simple as:
SqlQuery("SELECT * FROM #table", "Users")
Edit: Here are some things I've tried (Exception is an SqlException):
var result = context.Users.SqlQuery<T>("SELECT * FROM #p0 WHERE #p1 = '#p2'",
new SqlParameter("p0", tableName),
new SqlParameter("p1", propertyName),
new SqlParameter("p2", searchQuery));
This gives Must declare the table variable "#p0".
var result = context.Users.SqlQuery<T>("SELECT * FROM {0} WHERE {1} = '{2}'", tableName, propertyName, searchQuery);
This gives Must declare the table variable "#p0".
There is nothing wrong with your query syntax or how do you created and passed in the SqlParameter objects.
Your problem is that you try to use a variable as the table name, what you cannot do (see: Must declare the table variable #table), so you need to manually "template" the table name in your query:
Something like.
var result = context.Users.SqlQuery<T>(
"SELECT * FROM " + tableName + " WHERE #p0 = '#p1'",
new SqlParameter("p0", propertyName),
new SqlParameter("p1", searchQuery));

Categories

Resources