How to use oracle datetime instead of client datetime with Linq? - c#

I want to execute the script as below with Linq.
//Oracle script
UPDATE Table1 SET UPDATETIME = SYSDATE WHERE USERID = '1';
//Linq
var updateTbl = DbContext.Table1.Where(x=>x.USERID == "1").FirstOrDefalt();
updateTbl.UPDATETIME = DateTime.Now;
DbContext.SaveChange();
But after I retrieve the sql script, I found that Linq didn't use sysdate.
update "Table1"
set "UPDATETIME" = :p0
where ("USERID" = :p1)
-- :p0: '2021/3/4 09:55:07' (Type = DateTime) //DateTime on client instead of Oracle sysdate.
-- :p1: '1' (Type = String, Size = 128)
Some client will have wrong datetime, so I want to save datetime with oracle datetime instead of client datetime.
How to do it with Linq?
I want to execute the script like below.
update "Table1"
set "UPDATETIME" = :p0
where ("USERID" = :p1)
-- :p0: sysdate (Type = DateTime)
-- :p1: '1' (Type = String, Size = 128)

Entity framework doesn't update rows in sets. First, you retrieve the objects (your FirstOrDeault materialize the object), then you modify the objects in memory, and last EF generate update sentences for each modified object (in SaveChanges method).
Since the updateTbl.UPDATETIME = DateTime.Now is executed in memory, it does not execute SQL code. The update code is generated way after the value has changed.
If you need to execute SQL without retrieving the object, you could use DbContext.Database.ExecuteSqlCommand. This let you create arbitrary or parametrized SQL, but, if you are modifying other fields, it may be hard to maintain.
I assume running app server and database server are not synchronized, and want to use the DB server time. Could you force the servers to synchronize?
Other option could be using a trigger in the table that updates the column each time the row is inserted / updated.

Related

SQL stored procedure to pass date value in months/years

I am working on a C#/WPF application and connecting it with SQL.
I am trying to write a stored procedure in SQL that takes a selected date and converts it into (month, year) so at the time of executing, for example I put 1 for January and 2018 for the year and it will display the total sales for 2018 (that occurred in any given month in this case, January)
Ultimately in C#, the user will choose any given month from a comboBox, same for the year and click show sales and it should display using the stored procedure.
So far, I have this in SQL
ALTER PROCEDURE [dbo].[salesForSelectedMonth]
-- Add the parameters for the stored procedure here
#date date
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT SUM (TotalPrice) AS TOTAL_SALES, YEAR([TruckRental-PB].RentDate) AS year, MONTH([TruckRental-PB].RentDate) AS month
FROM [TruckRental-PB]
WHERE MONTH(#date) = MONTH([TruckRental-PB].RentDate)
AND YEAR(#date) = YEAR([TruckRental-PB].RentDate)
GROUP BY [TruckRental-PB].RentDate;
END
The issue is this is only allowing for putting a date then it shows the total sale
what I want is to get from C# the month (data type int), year (int) pass it to SQL proc to produce total sales
This is the logic I have so far (getting a datepicker value and passing it to the above proc) but getting an error still
public static int monthlySales (DateTime date)
{
using (Data_Context ctx = new Data_Context())
{
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).FirstOrDefault().ToString());
return sales;
}
System.InvalidOperationException: ''FromSqlRaw' or
'FromSqlInterpolated' was called with non-composable SQL and with a
query composing over it. Consider calling 'AsEnumerable' after the
method to perform the composition on the client side.'
UPDATE
I was able to pass month and year as int inside stored procedure however now it is showing the year as 1905 - any idea why?
-- Fetch matching month and year only
WHERE
#month = MONTH([TruckRental-PB].RentDate)
AND
#year = YEAR([TruckRental-PB].RentDate)
GROUP BY YEAR([TruckRental-PB].RentDate), MONTH([TruckRental-PB].RentDate)
Outcome
Your problem isn't really related to the type of parameter you pass, at least not your first problem. Your code
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).FirstOrDefault().ToString());
can't work this way. Entity Framework needs to map the result from FromSqlRaw to the entities it knows. But here you are returning an unknown result set where it doesn't know anything about its structure.
The workaround for this is to turn the result from EF into a memory bound collection and then use regular LINQ queries for the remaining code:
int sales = int.Parse(ctx.TruckRentalPbs.FromSqlRaw("salesForSelectedMonth", date).AsEnumerable().FirstOrDefault().ToString());
Then you can change the parameters by replacing the date parameter with two INT parameters and pass both into the query.

Determine SQL Server query (stored procedure) result type

I am planning to organize my data in SQL Server as a small orm of my own, creating classes of meta data on each in my code.
For the tests I am hard-coding the objects, the next step is to generate the properties of each using SQL Server queries about those objects.
And now that I deal with the stored procedures section of my code in C#,
I was wondering how it is possible to somehow use SQL Server to query the result type of the command executed?
For example, here we know what it's doing even by reading its name ...
[dbo].[GtallDrLFilesCount]
but another could select some other type of return such as rowset string etc'
Using the above stored procedure will return an int :
if(#AllDrives=1) Begin
Select
* From [dbo].[HddFolderFiles]
End
but the next (above) selects all content rather the RowsCount
I was planning to access SQL Server and query it's objects, and as I do not plan to set return parameter (OUT), is there a more elegant way to achieve it, rather than parsing the .sql file of the stored procedure?
Like if text contains SELECT * (this is a rowset) expect it with DataTable
if text contains Select COUNT(*) (this is int) prepare int type variable.
I thought in the case I did not assign an out parameter to my stored procedures can SQL Server tell the return type somehow even though it has no out parameter to make it easy for it?
I think you would have to execute the SProc to get it's columns, but you could do it without actually returing data using set fmtonly
Even sprocs that return a single value (eg - int) return a table when you use c# ... so you just need to take a look at the reader's Columns to get the data you want.
So:
set fmtonly on
exec [dbo].[MyStoredProc] 0
set fmtonly off
Will return a recordset which you can examine in c#
var adoCon = new System.Data.SqlClient.SqlConnection(_sConnectStr);
var adoCmd = new System.Data.SqlClient.SqlCommand("your SQL (above)", adoCon);
var Rows = adoCmd.ExecuteReader();
DataTable dtSchema = Rows.GetSchemaTable();
Now - you can wander through dtSchema to get columns. It's not pure SQL, but it's a c# + SQL approach. [dbo].[GtallDrLFilesCount] will return a single column table (column of type int).
Obviously - use a SQL command (not string). The next trick is translating SQL types into native c# types (easy for some data types and tricky for others ... take a look at ADOCommand's ReturnProviderSpecificTypes option).
Hope that helps!
From SQL Server 2012+ you can use sys.dm_exec_describe_first_result_set to read metadata about resultset:
This dynamic management function takes a Transact-SQL statement as a
parameter and describes the metadata of the first result set for the
statement.
SELECT *
FROM sys.dm_exec_describe_first_result_set(
N'EXEC [dbo].[MyProcedure]', NULL, 0);
SELECT *
FROM sys.dm_exec_describe_first_result_set(
N'SELECT * FROM [dbo].[tab]', NULL, 0);
SqlFiddleDemo
This method has limitation for more info read Remarks section

Specifying where clause format in Entity Framework with System.Data.SQLite

I have an Entity Framwework 4.0 Model running against an SQLite database to which I connect via System.Data.SQLite. I have one field in the database which is typed "Date", and formatted as yyyy-MM-dd. (As we know, SQLite has no internal Date or DateTime type).
The Entity Framework wizard happily translated that Date type to DateTime. When running queries against this date field, I was surprised to find out no results came.
Suppose a table "MyTable":
Create Table MyTable
(
Id Integer Not Null Primary Key,
ADate Date Not Null
);
With System.Data.SQLite and LINQ:
var date = new DateTime(2013, 1, 1);
context.MyTables.AddObject(new MyTable { Id = 0, ADate = date });
context.SaveChanges();
context.MyTables.Where(r => r.ADate == date).Count; // -> returns 0
Looking further with ToTraceQuery, I found out that the query became:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ADate] AS [ADate]
FROM [TestDate] AS [Extent1]
WHERE [Extent1].[ADate] = #p__linq__0
With testing, I discovered that the mapped variable p__linq__0 was transformed to a fixed format of yyyy-MM-dd hh:mm:ss, so that asking for DateTime(2013,1,1) meant the query was looking for '2013-01-01 00:00:00' when all that was to be found was '2013-01-01'.
If the folks who make 'System.Data.SQLite' had been nice about this, they'd have used the built in SQLite functions and done the comparison like:
WHERE datetime([Extent1].[ADate]) = datetime(#p__linq__0)
or even
WHERE date([Extent1].[ADate]) = date(#p__linq__0)
for just the date type. And indeed in System.Data.SQLite's SqlGenerator.cs, we find this formatting for all DateTime types:
((System.DateTime)e.Value).ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture), false /* IsUnicode */)
All this to say, is there a way to specify the format for this where clause in this context?
Notes: SQLite is what I'm stuck with, and the recorded format of 'yyyy-MM-dd' cannot be changed as other software relies on it.
One alternative to ExecuteStoreQuery is to pass other where clauses first (if any) then force the query to run (for example with ToList()), and finally to apply standard LINQ filters on the special format Date field afterwards.

Equality comparison fails between C# datetime and SQL datetime

I am trying to do an equality comparison between a C# datetime and a SQL datetime, which appears to fail due to the precision in which those values are stored.
So say I have a really simple SQL table, with these fields:
ID (PK, int, not null) - identity
Title (text, null)
UpdateTime (datetime, not null)
I create a class object via Entity framework, setting its UpdateTime to DateTime.Now like so:
DateTime now = DateTime.Now;
Title.UpdateTime = now;
When I insert my new object into the table, I see that all the values appear to be stored correctly. Now I want the ID that was created for my object.
This is where things get borked. I try pulling the ID back via LINQ:
Title.ID = context.DBTitles.Where(x=>x.UpdateTime == now).FirstOrDefault().ID;
This throws an exception because the query returns null, despite the fact that the 'now' I've inserted is supposedly the same as the 'now' that was inserted into my table.
So my question : How do I ensure that my C# datetime is equivalent to the datetime stored in SQL? What is the best way to get my ID back?
If you are using SQL server, use DateTime2 instead. It has the same precision as the .NET type.
If you're using Linq, won't the object you're inserting get the ID assigned to it upon commit? You won't need to 'recall' it.

Getting DB Server DateTime in application

I am using Entity framework and have 1 field in database AddedDate that is DateTime and not null, so I need to pass DateTime value.
But the problem is I have to pass DB Server datetime. How can I manage in this sceario or how can I get DB Server datatime to pass this.
I need to some unique solution, because I am this on many forms.
Edit: I need DB server Datetime upon insertion/updation in my application so that I can pass to entity framework object.
Thanks
Since you are using entity framework, you can do something like this:
var dateQuery = yourDbContext.CreateQuery<DateTime>("CurrentDateTime() ");
DateTime dateFromSql = dateQuery .AsEnumerable().First();
In general, if you use the entity framework and you use DateTime in a field, it will automatically do the back/forth conversion for you, just the same way it does so for integers, doubles etc.
Unless you mean something special, i.e., a char[40] field that must be filled with a DateTime value of a particular format.
You can get database server date and time by running SELECT GETDATE()) script.
Consider you have a table with 4 colums - the first 3 being strings and the last datetime, You can solve your issue by issueing INSERT SQL like this:
INSERT INTO myTable VALUES ('x', 'y', 'z', SELECT GETDATE())
Can't you use a stored procedure so you can get DB server Datetime very easily.
Just use getdate() in your query. For example:
INSERT INTO your_table (AddedDate, ...other columns) VALUES (getdate(), ...other values)
This basically asks the server to insert its own current date into the field; there's no need for you to retrieve it locally.

Categories

Resources