How to use stored procedures in EF Core 3.0 ?
I have tried the following
var user = await _context.Query<User>().FromSql("EXECUTE dbo.spGeneral_Authenticate").FirstOrDefaultAsync();
var user = await _context.Query<User>().FromSqlRaw("EXECUTE dbo.spGeneral_Authenticate").FirstOrDefaultAsync();
var user = await _context.Set<User>().FromSql("EXECUTE dbo.spGeneral_Authenticate").FirstOrDefaultAsync();
var user = await _context.Set<User>().FromSqlRaw("EXECUTE dbo.spGeneral_Authenticate").FirstOrDefaultAsync();
EF core translating the SQL in wrong way. I got the translated SQL from log file.
2019-09-27 11:21:36.086 +05:30 [Error] Failed executing DbCommand
("30"ms) [Parameters=[""], CommandType='Text', CommandTimeout='30']"
""SELECT TOP(1) [u].[FullName], [u].[Password], [u].[UserName] FROM (
EXECUTE dbo.spGeneral_Authenticate ) AS [u]" 2019-09-27 11:21:36.154 +05:30 [Error] An exception occurred while iterating over
the results of a query for context type '"__________Context"'."
""Microsoft.Data.SqlClient.SqlException (0x80131904): Incorrect syntax
near the keyword 'EXECUTE'. Incorrect syntax near ')'.
Translated SQL:
SELECT TOP(1) [u].[FullName], [u].[Password], [u].[UserName]
FROM (
EXECUTE dbo.spGeneral_Authenticate
) AS [u]
Microsoft.Data.SqlClient.SqlException (0x80131904): Incorrect syntax
near the keyword 'EXECUTE'. Incorrect syntax near ')'.
For the above error, we should use .ToList() or .ToListAsync() not .FirstOrDefault() or .FirstOrDefaultAsync()
It will work
var user = await _context.Set<User>().FromSql("EXECUTE dbo.spTest").ToListAsync();
It won't work
var user = await _context.Set<User>().FromSql("EXECUTE dbo.spTest").FirstOrDefaultAsync();
/*
Transalated SQL:
SELECT TOP(1) [u].[FullName], [u].[Password], [u].[UserName]
FROM (
EXECUTE dbo.spTest
) AS [u]
*/
The accepted answer nails it. Here are my two cents however:
Also, if you want to get only one result and still want to make the server call asynchronously:
var user = (await _context.Set<User>().FromSql("EXECUTE dbo.spTest").ToListAsync()).FirstOrDefault();
Related
I am trying to implement an upsert of an item into DynamoDB with optimistic locking. I have the update portion working with a ConditionExpression to check the version. But this fails the save portion as the ConditionExpression is false for saving. Is it possible to write the ConditionExpression so that it will handle both situations?
My code:
result = copy.copy(user)
table = get_db_table()
current_version = result.get_version()
result.update_version()
try:
table.put_item(
Item=result.to_table_item(),
ConditionExpression=Attr(result.get_version_key()).eq(current_version)
)
except ClientError as error:
logger.error(
"Saving to db failed with '%s'",
str(error))
# Restore version
result.set_version(current_version)
raise Exception(ErrorCode.DB_SAVE) from error
return result
Basically, you need to make sure the attribute exists before you can compare something to it. Your condition expression string should be
does_not_exist(current_version) or current_version = expected_current_version
Using Boto3, you can create this using
Attr(result.get_version_key()).not_exists() | Attr(result.get_version_key().eq(current_version))
I'm working on a Symfony 3.4 project and I'm trying to translate an sql query to DQL query but I get an Issue.
Mysql Query:
select sum(montant_paye)
from
(select montant_paye
from vente
where client_id = 1
and montant_paye > 0
order by date ASC
limit 2)
as T;
DQL Query (Error):
return $this->getEntityManager()
->createQuery('
SELECT SUM(montantPaye) as Total
FROM
SELECT v.montantPaye
FROM AppBundle:Vente v
where v.montantPaye > 0
AND v.client = '.$clientId.'
ORDER BY v.date ASC
limit 2
')
->getResult();
Error :
[Semantical Error] line 0, col 71 near 'SELECT v.montantPaye
': Error: Class 'SELECT' is not defined.
Is any one have a solution for a correct DQL query ?
Quoting from Christophe stoef Coevoet (Symfony Core Developer):
DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).
This is why it cannot be supported (supporting it only for the case you run the query without the hydration is a no-go IMO as it would mean that the query parsing needs to be dependant of the execution mode).
In your case, the best solution is probably to run a SQL query instead
(as you are getting a scalar, you don't need the ORM hydration anyway)
Details here.
add this function to your VenteRepository:
public function sumMontantPaye($clientId)
{
return $this->createQueryBuilder("v")
->select("sum(v.montantPaye) as sum")
->where("v.client = :id")
->andWhere("v.montantPaye > 0")
->setParameter("id", $clientId)
->setMaxResults(2)
->getQuery()->getSingleResult();
}
you can access the sum using $result["sum"] assuming $result is the variable assigned to this function in the controller
In a stored procedure that runs against the Azure Cosmos DB non-partitioned collection, I am running below select query:
var twentyMinutesBefore = new Date();
twentyMinutesBefore.setMinutes(twentyMinutesBefore.getMinutes() - 20);
var filterQuery = "SELECT TOP 40 * FROM c WHERE (c.transmissionState = 2 AND (" + twentyMinutesBefore + " > c.dateCreated.epoch)) OR c.transmissionState = 0 ORDER BY c.dateCreated.epoch DESC";
I execute the query as below:
var isAccepted = collection.queryDocuments(collectionLink, filterQuery, options, callback);
function callback(err, queryFeed, responseOptions) {
if (err) {
throw err; // <-- Error thrown from this line as per stack trace
}
// Iterate through query feed
}
I get the below error:
"Message": "Microsoft.Azure.Documents.DocumentClientException: Message:
{\"Errors\":[\"Encountered exception while executing function. Exception = Error:
{\\"errors\\":[{\\"severity\\":\\"Error\\",\\"location\\":{\\"start\\":63,\\"end\\":66},\\"code\\":\\"SC1001\\",
\\"message\\":\\"Syntax error, incorrect syntax near 'Dec'.\\"}]}
Stack trace: Error: {\\"errors\\":[{\\"severity\\":\\"Error\\",\\"location\\":{\\"start\\":63,\\"end\\":66},\\"code\\":\\"SC1001\\",\\"message\\":\\"Syntax error, incorrect syntax near 'Dec'.\\"}]}
In a Console application, I tried resolving the filter query to verify if it is properly formatted. It results as below:
SELECT TOP 40 * FROM c WHERE (c.transmissionState = 2 AND (1512593297244 > c.dateCreated.epoch)) OR c.transmissionState = 0 ORDER BY c.dateCreated.epoch DESC
When I copy this query as is and run in Cosmos DB query window, it runs fine and returns results as expected.
Not sure why it doesn't run through the stored procedure. Any idea what that 'Dec' means in the error? I don't find any such string in my stored procedure.
Use twentyMinutesBefore.getTime(), without getTime() to get the UNIX epoch time, you will get the full date like "Thu Dec 07 2017 13:26:39 GMT+1100 (AUS Eastern Daylight Time)":
var filterQuery = "SELECT TOP 40 * FROM c WHERE (c.transmissionState = 2 AND (" + twentyMinutesBefore.getTime() + " > c.dateCreated.epoch)) OR c.transmissionState = 0 ORDER BY c.dateCreated.epoch DESC";
I'm having some strange feeling abour sqlite3 parameters that I would like to expose to you.
This is my query and the fail message :
#query
'SELECT id FROM ? WHERE key = ? AND (userid = '0' OR userid = ?) ORDER BY userid DESC LIMIT 1;'
#error message, fails when calling sqlite3_prepare()
error: 'near "?": syntax error'
In my code it looks like:
// Query is a helper class, at creation it does an sqlite3_preprare()
Query q("SELECT id FROM ? WHERE key = ? AND (userid = 0 OR userid = ?) ORDER BY userid DESC LIMIT 1;");
// bind arguments
q.bindString(1, _db_name.c_str() ); // class member, the table name
q.bindString(2, key.c_str()); // function argument (std::string)
q.bindInt (3, currentID); // function argument (int)
q.execute();
I have the feeling that I can't use sqlite parameters for the table name, but I can't find the confirmation in the Sqlite3 C API.
Do you know what's wrong with my query?
Do I have to pre-process my SQL statement to include the table name before preparing the query?
Ooookay, should have looked more thoroughly on SO.
Answers:
- SQLite Parameters - Not allowing tablename as parameter
- Variable table name in sqlite
They are meant for Python, but I guess the same applies for C++.
tl;dr:
You can't pass the table name as a parameter.
If anyone have a link in the SQLite documentation where I have the confirmation of this, I'll gladly accept the answer.
I know this is super old already but since your query is just a string you can always append the table name like this in C++:
std::string queryString = "SELECT id FROM " + std::string(_db_name);
or in objective-C:
[#"SELECT id FROM " stringByAppendingString:_db_name];
I have this SQL query:
SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount
INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
[Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No]
WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
AND (tblAccount.[Account Type] NOT IN
('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <=
4 OR tblAccount.[State Change Date] IS NULL)
AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
CONTAINS(tblAccount.[Account Type], 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)
I have created a Linq query:
var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
"CA00", "CA01", "CA03", "CA04", "CA02",
"PA00", "PA01", "PA02", "PA03", "PA04"
};
var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };
var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
(account.StateChangeDate.Month - DateTime.Now.Month)
<= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment).ToList()
.Sum(minimumInstallment =>
Math.Abs((decimal)(minimumInstallment)));
return sum;
Are they equal/same ? I dont have records in db so I cant confirm if they are equal. In SQL there are brackets() but in Linq I didnt use them so is it ok?
Please suggest.
It is not possible for us to say anything about this, because you didn't show us the DBML. The actual definition of the mapping between the model and the database is important to be able to see how this executes.
But before you add the DBML to your question: we are not here to do your work, so here are two tips to find out whether they are equal or not:
Insert data in your database and run the queries.
Use a SQL profiler and see what query is executed by your LINQ provider under the covers.
If you have anything more specific to ask, we will be very willing to help.
The brackets will be generated by LINQ provider, if necessary.
The simplest way to check if the LINQ query is equal to the initial SQL query is to log it like #Atanas Korchev suggested.
If you are using Entity Framework, however, there is no Log property, but you can try to convert your query to an ObjectQuery, and call the ToTraceString method then:
string sqlQuery = (sum as ObjectQuery).ToTraceString();
UPD. The ToTraceString method needs an ObjectQuery instance for tracing, and the ToList() call already performs materialization, so there is nothing to trace. Here is the updated code:
var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
(account.StateChangeDate.Month - DateTime.Now.Month)
<= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment);
string sqlQuery = (sum as ObjectQuery).ToTraceString();
Please note that this code will not perform the actual query, it is usable for testing purposes only.
Check out this article if you are interested in ready-for-production logging implementation.
There can be a performance difference:
The SQL query returns a single number (SELECT Sum...) directly from the database server to the client which executes the query.
In your LINQ query you have a greedy operator (.ToList()) in between:
var sum = (...
...
select account.MinimumInstallment).ToList()
.Sum(minimumInstallment =>
Math.Abs((decimal)(minimumInstallment)));
That means that the query on the SQL server does not contain the .Sum operation. The query returns a (potentially long?) list of MinimumInstallments. Then the .Sum operation is performed in memory on the client.
So effectively you switch from LINQ to Entities to LINQ to Objects after .ToList().
BTW: Can you check the last proposal in your previous question here which would avoid .ToList() on this query (if the proposal should work) and would therefore be closer to the SQL statement.