I'm attempting to query for a specific record with an ID and am declaring the value of the ID but am still getting an error.
First I make the call to the db function:
specificEntity = await _db_FinancialEntityDb.GetFinancialEntity(id);
Then:
public Task<FinancialEntity_Model> GetFinancialEntity(int financialEntityID)
{
string sql = #"select fe.Id,
fe.EntityTypeID,
fe.Balance,
fe.InterestRate,
fe.OpenDate,
fe.MinimumPayment,
fe.APY,
fe.EntityName,
fe.InitialAmount,
fet.EntityType
from dbo.Financial_Entity fe
left outer join Financial_Entity_Type fet on fe.EntityTypeID = fet.Id
where fe.Id = #financialEntityID";
return _db.LoadDataObject<FinancialEntity_Model, dynamic>(sql, new { Id = financialEntityID });
}
And I'm using QueryFirstAsync:
var data = await connection.QueryFirstAsync<T>(sql, parameters);
But I keep getting this error:
System.Data.SqlClient.SqlException: 'Must declare the scalar variable "#financialEntityID".'
Is QueryFirstAsync the problem?
#financialEntityID should be #Id since that's the name you're passing to Dapper.
When you pass parameters as an anonymous type the property names should match the parameter names. eg
new { Id = financialEntityID }
would bind a parameter called #Id with the value of financialEntityID.
Related
I'm facing an error when inserting a JSON object into a VARIANT data type column, from within a stored procedure in Snowflake.
Below is the reference code:
create or replace procedure test1234()
returns varchar not null
language javascript
as
$$
var birthDateVar = 'BIRTH_DATE';
var genderVar = 'GENDER';
var countryVar = 'COUNTRY';
var loanVar = 'LOAN_AMOUNT';
var emailVar = 'EMAIL';
var tableName = 'SF_STRUCT_STAGE_RAW';
var UPDATE_DATE = "2019-01-01";
var email = "XXX#gmail.com";
var row_num = "1";
var person_id = "1";
var EMAILERROR = {
"row_num": row_num,
"person_id": person_id,
"tableName": tableName,
"fieldName": emailVar,
"fieldValue": email,
"errorDesc": 'value is invalid email'
};
var cmd = "insert into error_details_log values(:1,:2);";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
binds: [EMAILERROR, UPDATE_DATE]
}
);
stmt.execute();
return emailError;
$$;
Inserting Object types via binding variables directly is not currently supported from within Stored Procedures. Quoting the relevant portion from the Snowflake documentation:
When you bind JavaScript variables to SQL statements, Snowflake converts from the JavaScript data types to the SQL data types. You can bind variables of the following JavaScript data types:
number
string
SfDate
However, the example in the documentation for TIMESTAMP datatypes involving use of strings and recasting can be adapted for your use-case, using the PARSE_JSON(…) function and JSON.stringify(…) JavaScript API:
[…]
// Convert Object -> String
var EMAILERROR_str = JSON.stringify(EMAILERROR);
// Ask Snowflake to parse String as JSON (String -> Object)
var cmd = "insert into error_details_log select PARSE_JSON(:1), :2;";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
// Bind the String value, not the Object one
binds: [EMAILERROR_str, UPDATE_DATE]
}
);
[…]
Here I write a stored procedure for deleting records; it's working fine in SQL. But when I try to load it in MVC JSON format it threw an error:
implementation of the query pattern for source type 'int'. 'Select' not found"
Stored procedure:
ALTER procedure [dbo].[AccessorDataDelById]
#ID int
AS
BEGIN
DELETE FROM Accessors
WHERE Id = #ID
END
JSON format:
public JsonResult GetAssdata(int iD = 0)
{
var x = (from n in db.AccessorDataDelById(iD)
select n).FirstOrDefault();
return new JsonResult { Data = x, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
var x=db.AccessorDataDelById(iD)
Consider this simple query which use full text searching on the Keywords field:
DECLARE #searchTerm VARCHAR(500) = 'painted'
SELECT * FROM StockCatalogueItems
WHERE (CONTAINS(KeyWords, #searchTerm))
This works as expected, but I need to do the same using a Dapper.net parameterised query. When using stored procedures, I create the full text parameter like this: "\"painted*\""
But using the same approach this doesn't work using dapper. No results are returned. This is the line in the query where I use the parameter:
AND (CONTAINS(KeyWords, #search))
and it's passed to the query like so:
return _context.Database.Connection.Query<StockProfileMatrix>(basequery, new
{
search = searchTerm
}
I can only assume that dapper is sanitising the string somehow, removing quotes perhaps?
Any ideas?
This works for me. However the tech stack am working on is .net core RTM and "Dapper": "1.50.0-rc3",
_dbConnection.QueryAsync<Guid>(#"select br.Id from Brand br where CONTAINS(br.Text,#Name)",new {Name = $"\"*{name}*\""}))
For completeness, I'll answer the question. The query syntax is correct, but the way in which the full-text parameter is created was obviously not. I created an extension method that formats the parameter:
public static string ToFullText(this string str)
{
string searchTerm = null;
if (!string.IsNullOrEmpty(str))
{
string[] keywords = str.Trim().Split(null);
foreach (var keyword in keywords)
{
searchTerm += string.Format("\"{0}*\" AND ", keyword);
}
if (searchTerm != null)
searchTerm = searchTerm.Substring(0, searchTerm.LastIndexOf(" AND "));
}
return searchTerm;
}
Then I call the method when I pass the parameter in to the dapper query:
_context.Database.Connection.Query<dynamic>(query, new
{
search = filter.SearchTerm.ToFullText()
});
I'm not sure how to format the string request to edge-sql in order to execute a stored procedure that requires parameters. If I change the stored procedure to not use parameters and just send exec sp_III_UpdateOperMgr it executes properly.
Below is the syntax I am using in edge-sql that returns the error
"Could not find stored procedure 'sp_III_UpdateOperMgr
#quoteNumber,#poNumber'."
var updateOpMgrSql = edge.func('sql',{
connectionString: GM_CONNECTION_STRING,
source:function () {
/*
exec sp_III_UpdateOperMgr #quoteNumber,#poNumber
*/
},
});
Below is the syntax used in MS SQL Server Management Studio that executes properly
exec sp_III_UpdateOperMgr #quoteNumber='121715JM-1',#innovationJobNumber='999999'
Assuming that the parameters in the stored procedure itself are #quoteNumber and #poNumber can you try:
var updateOpMgrSql = edge.func('sql',{
connectionString: GM_CONNECTION_STRING,
source:function () {
/*
exec sp_III_UpdateOperMgr #quoteNumber=#quoteNumberParam,#poNumber=#poNumberParam
*/
},
});
Then call the updateOpMgrSql function with:
updateOpMgrSql({ quoteNumberParam: 10, poNumberParam: 15 }, function (error, result) {
if (error) throw error;
console.log(result);
});
I don't know if it there is a better way but I ended up editing the C sharp code being used by the JavaScript.I had to add a split on the first empty space after the SP name then take the first item in the array which would be the actual name of the procedure.
Before it was including the all the parameters passed when needing the SP name only
commandString.Substring(5).TrimEnd()
After I get the first item in the array by splitting the string on the first white space
commandString.Substring(5).Split(' ')[0].TrimEnd()
async Task<object> ExecuteStoredProcedure(
string connectionString,
string commandString,
IDictionary<string, object> parameters)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
var spName = commandString.Substring(5).Split(' ')[0].TrimEnd();
SqlCommand command = new SqlCommand(spName, connection)
{
CommandType = CommandType.StoredProcedure
};
using (command)
{
return await this.ExecuteQuery(parameters, command, connection);
}
}
}
I got it to work for me. This syntax works as well. You don't have to write the parameters in the sql code. You only need to include them in the javascript parameters as you will see below. Here is my stored procedure:
create procedure [dbo].[p_Test]
#p nvarchar(max) = null
as
begin
select * from [registration].[User]
where UserName = #p
end
You can swap out the table and parameter in the example above to suit your particular database.
Here is my edge code:
var getUser = edge.func('sql', function () {
/*
exec [dbo].[p_Test]
*/
});
getUser({p:'SomeUserName'}, function (error, result) {
if (error) throw error;
console.log(result);
});
I have a database table which has a bunch of fields including one called Type and another called Code. I also have a list of Type and Code pairs that are encapsulated in a class. Something like this:
public class TypeAndCode
{
public byte Type { get; set; }
public int Code { get; set; }
// overrides for Equals and GetHashCode to compare if Type and Code are equal
}
Now what I need to do is select from the table only those entries who type AND code match an entry in my collection. So, for example, I tried something like this:
var query = myTable.Where(a => myTCList.Contains(new TypeAndCode() { Type = a.Type, Code = a.Code }).ToList();
But it'll give me a NotSupportedException:
Unable to create a constant value of type 'TypeAndCode'. Only primitive types
or enumeration types are supported in this context.
Is there a way to make this work so that I can retrieve from the database only those entries that have a Code and Type that match my list of Code and Type? I'm trying to avoid having to retrieve all the entries (it's a big table) and match them in memory.
I'm aware that I could try something like
var query = myTable.Where(a => listOfTypes.Contains(a.Type) && listOfCodes.Contains(a.Codes))
But that will make some spurious matches where the type and code are from different pairs in my original list.
You can use Any instead:
var query = myTable
.Where(a => myTCList.Any(t => t.Type == a.Type && t.Code == a.Code ))
.ToList();
You should be able to just do this manually without the overloaded methods from your class:
myTCList.Any(x => x.Type == a.Type && x.Code == a.Code)
My ulitmate solution here, in case anybody else encounters a similar problem, was to set up a temporary table that I could write the pairs I wanted to match to which I could them join with the database table. After doing the join and materializing the results, you can delete the temporary table.
Something like:
ctx.myTempTable = (from pair in mypairs
select new myTempTable() { Type = pair.Type, Code = pair.Code }).ToList();
ctx.SaveChanges();
var query = from q in myTable
join t in ctx.myTempTable
on new { q.Type, q.Code } equals new { t.Code, t.Type }
select q;
The whole thing is in a try/catch/finally block with the finally block used to clear up the temporary table(s)