Compare Two date "Strings" Sqlite using Nhibernate - sqlite

I am using SQLite and NHibernate and Im storing my date as Strings on SQLite since I cant store as Date.
Everything was just fine until a need to compare dates.. I tried the following codes:
var initialDate = DateTime.Parse(_InitialDate);
var finalDate = DateTime.Parse(_FinalDate);
return session.QueryOver<Locacoes>()
.Where(c => DateTime.Parse(c.InitialDate) >= initialDate )
.Where(c => DateTime.Parse(c.FinalDate) <= finalDate).List();
but I got an exception on the first "Where": "a variable 'c' of type 'Locacoes' is referenced on scope '', but it is not defined".
How can I compare date on SQLite using NHibernate?
I've tried many things with above code, but didnt work.
Edit: Its not duplicate, the error can be the same, but the result is different

First, while Sqlite likes to pretend everything is a string, that should be considered a storage format and NO REASON why your object model should use strings to hold date values. Your object model should of course type the properties as DateTime or DateTimeOffset. Then configure your NHibernate mappings properly to map the values to what SQLite can handle (actually I think NHibernate would handle that automatically if you just tell it to use the SQLiteDialect).
Second, I don't think QueryOver() can handle things like DateTime.Parse(). Don't confuse QueryOver() with Linq2NHibernate (the Query() method), which have more advanced expression interpretation abilities. On the other hand, you no longer need to use Parse() when you begin to use correct types in your object model.
At least if you use LINQ, it should be able to handle DateTime.Date for SQLite, if you need it:
session.Query<Locacoes>()
.Where(l => c.InitialDate.Date >= initialDate)
Of course, you would only need to put Date in there if there is a non-zero time-of-day component that you need to ignore.

Related

How to insert an element into the middle of an array (json) in SQLite?

I found a method json_insert in the json section of the SQLite document. But it seems to be not working in the way that I expected.
e.g. select json_insert('[3,2,1]', '$[3]', 4) as result;
The result column returns '[3,2,1,4]', which is correct.
But for select json_insert('[3,2,1]', '$[1]', 4) as result;
I am expecting something like '[3,2,4,1]' to be returned, instead of '[3,2,1]'.
Am I missing something ? I don't see there is an alternative method to json_insert.
P.S. I am playing it on https://sqlime.org/#demo.db, the SQLite version is 3.37.2.
The documentation states that json_insert() will not overwrite values ("Overwrite if already exists? - No"). That means you can't insert elements in the middle of the array.
My interpretation: The function is primarily meant to insert keys into an object, where this kind of behavior makes more sense - not changing the length of an array is a sacrifice for consistency.
You could shoehorn it into SQLite by turning the JSON array into a table, appending your element, sorting the result, and turning it all back into a JSON array:
select json_group_array(x.value) from (
select key, value from json_each('[3,2,1]')
union
select 1.5, 4 -- 1.5 = after 1, before 2
order by 1
) x
This will produce '[3,2,4,1]'.
But you can probably see that this won't scale, and even if there was a built-in function that did this for you, it wouldn't scale, either. String manipulation is slow. It might work well enough for one-offs, or when done infrequently.
In the long run, I would recommend properly normalizing your database structure instead of storing "non-blob" data in JSON blobs. Manipulating normalized data is much easier than manipulating JSON, not to mention faster by probably orders of magnitude.

Delphi - ClientDataSet SQL calculated field causing "Invalid field type" error at runtime [duplicate]

Using Delphi 10.2, SQLite and Teecharts. My SQLite database has two fields, created with:
CREATE TABLE HistoryRuntime ('DayTime' DateTime, Device1 INTEGER DEFAULT (0));
I access the table using a TFDQuery called qryGrpahRuntime with the following SQL:
SELECT DayTime AS TheDate, Sum(Device1) As DeviceTotal
FROM HistoryRuntime
WHERE (DayTime >= "2017-06-01") and (DayTime <= "2017-06-26")
Group by Date(DayTime)
Using the Field Editor in the Delphi IDE, I can add two persistent fields, getting TheDate as a TDateTimeField and DeviceTotal as a TLargeIntField.
I run this query in a program to create a TeeChart, which I created at design time. As long as the query returns some records, all this works. However, if there are no records for the requested dates, I get an EDatabaseError exception with the message:
qryGrpahRuntime: Type mismatch for field 'DeviceTotal', expecting: LargeInt actual: Widestring
I have done plenty of searching for solutions on the web on how to prevent this error on an empty query, but have had not luck with anything I found. From what I can tell, SQLite defaults to the wide string field when no data is returned. I have tried using CAST in the query and it did not seem to make any difference.
If I remove the persistent fields, the query will open without problems on an empty return set. However, in order to use the TeeChart editor in the IDE, it appears I need persistent fields.
Is there a way I can make this work with persistent fields, or am I going to have to throw out the persistent fields and then add the TeeChart Series at runtime?
This behavior is described in Adjusting FireDAC Mapping chapter of the FireDAC's SQLite manual:
For an expression in a SELECT list, SQLite avoids type name
information. When the result set is not empty, FireDAC uses the value
data types from the first record. When empty, FireDAC describes those
columns as dtWideString. To explicitly specify the column data type,
append ::<type name> to the column alias:
SELECT count(*) as "cnt::INT" FROM mytab
So modify your command e.g. this way (I used BIGINT, but you can use any pseudo data type that maps to a 64-bit signed integer data type and is not auto incrementing, which corresponds to your persistent TLargeIntField field):
SELECT
DayTime AS "TheDate",
Sum(Device1) AS "DeviceTotal::BIGINT"
FROM
HistoryRuntime
WHERE
DayTime BETWEEN {d 2017-06-01} AND {d 2017-06-26}
GROUP BY
Date(DayTime)
P.S. I did a small optimization by using BETWEEN operator (which evaluates the column value only once), and used an escape sequence for date constants (which, in real you replace by parameter, I guess; so just for curiosity).
This data type hinting is parsed by the FDSQLiteTypeName2ADDataType procedure that takes and parses column name in format <column name>::<type name> in its AColName parameter.

CLR DateTime object comparison with SQL Server DateTime

I'm using this implementation to conduct server side searching using Entity Framework for jqGrid. The issue that I'm having is that although the search is working fine for text or numerical fields, searching using DateTime values isn't working.
The problem is that the DateTime object in my model class sends the string representation of the object (i.e. in the format 2/9/2014 12:00:00 AM) to the database but the database is formatted as 2014-09-03 00:00:00:000. As a result, the comparison always fails.
I can't change my DateTime property to a string so I'm stumped. The resultset is returned via a stored procedure (a simple SELECT * FROM [TableName]) so I tried formatting the associated Date field and returning that but it returns as an nvarchar.
Has anyone encountered this before or have any recommendations as to how to resolve this issue? I'd appreciate any help, thanks!
Just to provide an answer for anyone who comes across this. I took the following steps to resolve this issue:
1) Made the following change in the JQGrid support class:
_formatObjects.Add(parseMethod.Invoke(props[rule.field], new object[] { rule.data }));
to
_formatObjects.Add(parseMethod.Invoke(props[rule.field], new object[] { (parseMethod.ReturnType.FullName == "System.DateTime" && rule.data != "") ? Convert.ToDateTime(rule.data, CultureInfo.CreateSpecificCulture("fr-FR")).ToString() : rule.data }));
2a) In my controller, I added the following bit of code whenever I was fetching directly from the table (you have to specify the column names explicitly to truncate the time portion):
//For matching date instead of datetime values
if (wc.Clause.Contains("Date"))
{
wc.Clause = wc.Clause.Replace("DeliveryDate", "DbFunctions.TruncateTime(DeliveryDate)");
}
results = results.Where(wc.Clause, wc.FormatObjects);
2b) If the data was being returned from a stored procedure, I just returned an appropriate Date field from the SP (this approach will work for DateTime fields only if the timestamp portion is all zeros).
Hope this helps someone else.

F# query expressions - restriction using string comparison in SqlProvider with SQLite

SQLite doesn't really have date columns. You can store your dates as ISO-8601 strings, or as the integer number of seconds since the epoch, or as Julian day numbers. In the table I'm using, I want my dates to be human-readable, so I've chosen to use ISO-8601 strings.
Suppose I want to query all the records with dates after today. The ISO-8601 strings will sort properly, so I should be able to use string comparison with the ISO-8601 string for today's date.
However, I see no way to do the comparison using the F# SqlProvider type provider. I'm hoping that this is just a reflection of my lack of knowledge of F# query expressions.
For instance, I can't do:
query {
for calendarEntry in dataContext.``[main].[calendar_entries]`` do
where (calendarEntry.date >= System.DateTime.Today.ToString("yyyy-MM-dd hh:mm:ss"))
... }
I get:
The binary operator GreaterThanOrEqual is not defined for the types 'System.String' and 'System.String'.
I also can't do any variation of:
query {
for calendarEntry in dataContext.``[main].[calendar_entries]`` do
where (calendarEntry.date.CompareTo(System.DateTime.Today.ToString("yyyy-MM-dd hh:mm:ss")) >= 0)
... }
I get:
Unsupported expression. Ensure all server-side objects appear on the left hand side of predicates. The In and Not In operators only support the inline array syntax.
Anyone know how I might do string comparisons in the where clause? It seems that my only option for filtering inside the query is to store seconds-since-epoch in the database and use integer comparisons.
This was a temporary bug with old SQLProvider version and it should be working now. If not, please open a new issue to the GitHub repository: https://github.com/fsprojects/SQLProvider

L2Entities, stored procedure and mapping

Finally checked out L2E framework and ran into problems almost instantly.
Yeah, i know... i should read some books before.
Situation:
entity with props -> id and name.
entity is mapped to table, which has id and name columns.
sproc, which returns ONLY id column.
Problem:
ObjectResult<MyProp> result = _container.MyStoredProcedure(uberParameter);
Calling this will cause an error
[guilty method goes here] threw exception:
System.Data.EntityCommandExecutionException: The data reader is incompatible with the specified 'DataBase.MyPropTableObject'. A member of the type, 'name', does not have a corresponding column in the data reader with the same name..
Problem #2:
Can`t "just return" that field, cause that column has XML data type, but sproc uses fancy select statements, which causes:
Msg 421, Level 16, State 1, Line 1
The xml data type cannot be selected as DISTINCT because it is not comparable.
Question:
Is it possible to exclusively turn off mapping for this entity prop only for this one sproc?
Problem 1 is due to the proc not having the columns to populate the entity. You don't really need the proc if you have mapped the table, just select the field you want from it using linq
var result = MyEntities.EntityIMapped.First(r => r.id = uberParameter).Name;
Would give you the value from the Name column of the table for the given id. You don't need to use a stored proc for this.
Problem 2 sounds like it is in the proc, I would think that distinct on an xml data column would give a lot of results, but I'm only guessing as I don't know your solution.
This is not a direct answer for your question but, hopefully it will point you in the right direction.

Resources