How to call a stored procedure from MVC that requires datetimes - c#

I'm wanting to call this stored procedure with input parameters:
proc [dbo].[Invoice_GetHomePageInvoices] (
#FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
Trouble with this is the way I usually call a stored proc from my code is:
return _db.Database.SqlQuery<HomePageInvoice>(string.Format("EXEC Invoice_GetHomePageInvoices #FinancialYearStartDate = '{0}', #FinancialYearEndDate = '{1}'", financialYear.StartDate.ToString(), financialYear.EndDate.ToString()));
So this isn't going to work because I've basically converted my datetimes to strings.
How the heck am I supposed to do this?

You should use sql parameters, basically like this:
var startDate = new SqlParameter("FinancialYearStartDate", dateTimeValueHere);
var endDate = new SqlParameter("FinancialYearEndDate", dateTimeValueHere);
return _db.Database.SqlQuery<HomePageInvoice>("Invoice_GetHomePageInvoices", startDate, endDate);
More info: How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5

convert the date to a string with specific format.
use SQL code to convert it back to an sql datetime object.
When using sql server (microsoft):
http://msdn.microsoft.com/en-us/library/ms187928.aspx
"convert(datetime, '{0}', 103)", financialYear.EndDate.ToString("MM/dd/yyyy")
edit: Ropstah's method is actually better, this is just the way I used to do it :P

Related

String was not recognized as a valid DateTime, stored procedure empty parameter

I wrote a stored procedure in SQL Server. I have a parameter of type smalldatetime. I want to send this parameter blank when I run it with LINQ. When I want to send it, I get this error.
String was not recognized as a valid DateTime.
How can I send the date format blank?
C#, LINQ;
var query = ctx.onayListele(Convert.ToDateTime(dataList.olusturulmaTarihi)).ToList();
SQL:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi smalldatetime = NULL
AS
BEGIN
SELECT
Onay.onayID, alep.olusturulmaTarihi, TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM
Onay
WHERE
(#var_olusturmaTarihi IS NULL OR
CONVERT(DATE, Talep.olusturulmaTarihi) = CONVERT(DATE, #var_olusturmaTarihi))
END
At first, I thought you needed to change your stored procedure.
Now that I've read the question again, I've realized that the error message comes from the c# side, not from the stored procedure (that I still think you should change).
Attempting to convert a null or empty string to DateTime will result with the error in your question. To avoid that, you need to make sure the string can in fact be converted to DateTime before sending it to the stored procedure:
DateTime datetime;
DateTime? olusturulmaTarihi = null;
if(DateTime.TryParse(dataList.olusturulmaTarihi, out datetime))
{
olusturulmaTarihi = (DateTime?)datetime;
}
var query = ctx.onayListele(olusturulmaTarihi).ToList();
This way, you will send null to the stored procedure if the string can't be parsed as DateTime, and avoid the error.
As to the stored procedure, I would suggest writing it like this instead:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi date = NULL
AS
BEGIN
SELECT Onay.onayID,
alep.olusturulmaTarihi,
TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM Onay
WHERE #var_olusturmaTarihi IS NULL
OR CONVERT(date,Talep.olusturulmaTarihi) = #var_olusturmaTarihi
END
Please note that if you have an index on Talep.olusturulmaTarihi, this stored procedure will not be able to use it. In that case, you better use something like this instead:
ALTER PROCEDURE [dbo].[onayListele]
#in_olusturmaTarihi date = NULL
AS
BEGIN
SELECT Onay.onayID,
alep.olusturulmaTarihi,
TalepTuru.talepTuruAdi,
TalepDurumu.talepDurumuAciklamasi
FROM Onay
WHERE #var_olusturmaTarihi IS NULL
OR
(
Talep.olusturulmaTarihi >= CAST(#var_olusturmaTarihi as datetime) -- or whatever the data type of the column is
AND Talep.olusturulmaTarihi < DATEADD(DAY, 1, CAST(#var_olusturmaTarihi as datetime)) -- or whatever the data type of the column is
)
END

Stored procedure not executing correctly through entity framework

When I run the below stored procedure in SQL Management Studio, it runs as expected and takes around 5 minutes to complete.
exec [dbo].[sproc] '2016-02-01', '2016-02-29'
However, when running using Entity Framework it seems to takes 1 second and not actually do what it's supposed to do, even though I'm passing in the same parameters
Could this be a configuration issue?
I'm passing the connection string name into the DbContext constructor and the above is running in a thread due to timeouts
new Thread(new ThreadStart ( delegate ()
{
using (var context = new MyDbContext())
{
var d1 = new SqlParameter("Date_From", dateFrom);
var d2 = new SqlParameter("Date_To", dateTo);
int result = context.Database.ExecuteSqlCommand("exec [dbo].[sproc] #Date_From, #Date_To", d1, d2);
}
})).Start();
-- Update --
The Stored procedure expects a date time and although I can run it locally with a string (it will convert it to datetime), it will not run through ExecuteSqlCommand unless I pass the parameters as DateTimes. Surely if I'm passing a datetime parameter it should know which are days, months and years?
ALTER PROCEDURE [dbo].[sproc]
(
#Date_From AS DATETIME,
#Date_To AS DATETIME
)
-- Update --
The following is being executing when checking through SQL Profiler
exec sp_executesql N'exec [dbo].[sproc] #Date_From, #Date_To',N'#Date_From datetime,#Date_To datetime',#Date_From='2016-02-01 00:00:00',#Date_To='2016-02-29 00:00:00'
If I run this manually in SQL Server Manager I get the following error:
Error converting data type varchar to datetime.
User / Security / DB Settings?
Probably an issue with the date that ToShortDateString() produces as it's not going to format the date like 2016-02-01. It will produce a date based on the culture that it's running under, so will output something like this from the above link:
// Displaying short date for en-US culture:
// 6/1/2009 (Short Date String)
SQL Server may not format this value ('2016-02-01') correctly when using .ToShortDateString(), it might get the day and month the wrong way round, which could explain your unexpected results.
A quick test you can run in SQL Server Management Studio:
SELECT CAST('01/02/2016' AS DATE)
Does it produce: 2016-01-02 or 2016-02-01?
You can also debug the application with a breakpoint on this line:
int result = context.Database.ExecuteSqlCommand("exec [dbo].[sproc] #Date_From, #Date_To", d1, d2);
You can check the values in the paramters d1 and d2, to ensure the format is as you expect.
from your statements:
new Thread(new ThreadStart ( delegate ()
{
using (var context = new MyDbContext())
{
var d1 = new SqlParameter("Date_From", dateFrom.ToShortDateString());
var d2 = new SqlParameter("Date_To", dateTo.ToShortDateString());
int result = context.Database.ExecuteSqlCommand("exec [dbo].[sproc] #Date_From, #Date_To", d1, d2);
}
})).Start();
and
ALTER PROCEDURE [dbo].[sproc]
(
#Date_From AS DATETIME,
#Date_To AS DATETIME
)
You should not be doing dateFrom.ToShortDateString()); and dateTo... - your dateFrom and dateTo are already datetimes, as the SP requires. You're currently passing a string into a datetime parameter. Fix that, and you should be good I would think.
Also, this is a leap year, could you have some weird date mathing logic not taking that into account?
The stored procedure only seemed to execute when the date time was formatted to ISO8601. This is achieved by calling ToString with "s" as the argument
var d1 = new SqlParameter("Date_From", dateFrom.ToString("s"));
var d2 = new SqlParameter("Date_To", dateTo.ToString("s"));
Result
2016-02-01T12:00:00
I had a similar issue where I was getting the exception,
Error converting data type nvarchar to datetime.
I had to change the sql string to
int result = context.Database.ExecuteSqlCommand("exec [dbo].[sproc] #Date_From = #Date_From, #Date_To = #Date_To", d1, d2);
For some reason when adding the #Parameters I needed to set them equal to the SqlParameter name. So #Date_From, #Date_To = #Date_To..."

How can I cast specific part of string type query to date to avoid "ORA-01843: not a valid month" error?

So I am trying to backup failed queries when the database is down and execute them immediately after database is ready. So far I am saving all the failed queries in text file. When the database is up I execute those failed queries line by line from the file. Since those failed queries are stored in string format, when I execute them for Oracle database (one column's datatype is date) I get ORA-01843: not a valid month.
e.g
INSERT INTO my_table ("MODULE", "USERNAME", "COMPUTER", "DATE","NAME", "EMAIL" ) values ('mymodule', 'mmouse', 'mickey007', '06-03-2015 12:05:00', 'Mickey Mouse', 'mmickey#gmail.com')
Since there is going to be a lot of this kind queries in the fail_queries file what could be the ways to cast just '06-03-2015 12:05:00' part of string to date
Thanks beforehand!!!
Do not pass DateTime as string, instead use Parameters.
If you have to pass a string then you have to convert it to date using TO_DATE like in your case:
TO_DATE('06-03-2015 12:05:00', 'dd-mm-yyyy hh24:mi:ss')
But, if you are sending values through C#, then instead of concatenating values, use Parameters. like:
using(OracleConnection connection = new OracleConnection("yourConnectionString"))
using (
OracleCommand command =
new OracleCommand(#"INSERT INTO my_table (MODULE, USERNAME, COMPUTER, DATE,NAME, EMAIL )
values (:myModule, :mmouse,:mickey007, :myDateTime,:myothercol, :myEmail", connection))
{
//add parameters
command.Parameters.Add(":myModule", OracleDbType.Varchar2).Value = "myModule";
command.Parameters.Add(":myDateTime", OracleDbType.Date).Value = DateTime.Now; // like this
//add other parameters similarly.
connection.Open();
//execute command
}
Parameters will not only save you from errors like these, but also save you from SQL Injection.

how to convert string into DateTime in where Clause?

i have to compare a choosen Date from a Calendar (startdat & enddat) with a Date in my SQL 2008 R2 DB. I have to write it with LINQ, but in the view i have, the DateTime is converted to a String (Varchar) so i have to convert it in my LINQ Query back to DateTime. My basic Query looks like this now:
var reportlist = (from r in context.Monthly_Report
where r.CreateDate >= startdat && r.CreateDate <= enddat
select r.Ticketnumber).ToList();
So the CreateDate i get is a String and for comparing i've to convert it. I've tried it with Convert.ToDateTime() but there's is the Problem with L2E.
So how can i convert it like in a SQL Script or that SQL knows what i means?
Thanks for every help i get. (btw i'm not allowed to change the view)
You can only use a reduced set of functions in Linq to Entities. This functions will be transalated to DB functions.
You can use:
canonical functions: they're availabel for all the providers (DB tastes)
entity functions: exposes canonical functions in the EDM
db functions: exposes canonical functions in the EDM
sql functions: exposes SQL Server specific functions
None of these groups includes a function that can convert from string to datetime, so there is no way to do it directly.
You must look for alternatives:
Create a DB view which exposes the "stringified" datetime as a datetimecolumn and query it
Create a stored proc and use it
Convert the datetime to string and compare it, if at all possible (this depends on how the "stringified" datetime looks like)
You can use the previous solution using substrings (which will map to DB functions). This will work for all cases: reorder the y, m, d, of the "stringified" dt date, so that it looks like "yyyymmdd". Then convert your startdat and enddat to the same format, and compare it in string (alphabetic) order.
Fundamentally, you need your view to return a datetime.
However, there are a couple of ways to do this.
1) You could pull your data out as a string into a list object. Then you wouldnt be using L2E.
var temp = (from r in context.Monthly_Report
select new { r.Ticketnumber, r.CreateDate} ).ToList();
var reportList = temp.Where(r =>
Convert.ToDateTime(r.CreateDate) >= startdat &&
Convert.ToDateTime(r.CreateDate) <= enddat)
2) You could convert your datetime to a string value and compare it.
var reportlist = (from r in context.Monthly_Report
where r.CreateDate.CompareTo(startdatasstring) >= 0 &&
r.CreateDate.CompareTo(enddatasstring) <= 0
select r.Ticketnumber).ToList();

How to call a stored procedure from MVC that requires a list of ids

I got a good answer to my previous question but it's actually even more complicated:
I need to pass to this stored procedure a list of ints:
ALTER proc [dbo].[Invoice_GetHomePageInvoices] (
#AreaIdList varchar(max)
, #FinancialYearStartDate datetime = null
, #FinancialYearEndDate datetime = null
Here's what I have so far:
public virtual IEnumerable<HomePageInvoice> GetHomePageInvoices(IList<Area> areas, FinancialYearLookup financialYear)
{
var areaIds = areas.Select(x => x.Id).ToList();
//return _db.Database.SqlQuery<HomePageInvoice>(string.Format("EXEC Invoice_GetHomePageInvoices #AreaIdList = '{0}', #FinancialYearStartDate = '{1}', #FinancialYearEndDate = '{2}'", areas.ToString(), financialYear.StartDate.ToString(), financialYear.EndDate.ToString()));
var startDate = new SqlParameter("FinancialYearStartDate", financialYear.StartDate);
var endDate = new SqlParameter("FinancialYearEndDate", financialYear.EndDate);
return _db.Database.SqlQuery<HomePageInvoice>("Invoice_GetHomePageInvoices", startDate, endDate);
}
So the the datetime parameters are sorted. But how would you send the ids to the stored proc given I current have a List<int> and sql expects #AreaIdList varchar(max)
String.Join?
String.Join(",", areaIds)
Table-valued parameters, you should really read the post below. He does a fantastic job at explaining how it all should work
http://www.sommarskog.se/arrays-in-sql-2008.html
Convert your List<int> to a comma-separated string, and pass that to your stored procedure.
Converting a generic list to a CSV string
I really depends on what you are doing with that list. But if you are using it for an IN clause or something like that then I would build that out in C# and pass it to the proc:
StringBuilder s = new StringBuilder();
foreach (var i in areaIds)
{
s.Append(String.Format("'{0}',", i));
}
s.TrimEnd(',');
var areas = new SqlParameter("AreaIdList", s.ToString());
Then in the proc you can use it like:
WHERE area IN #AreaIdList

Categories