Expression Tree for .NET DateTime <> Oracle Timestamp like search - c#

I need to know whether I can get a clue or not.
I am trying to build an Expression Tree that is evaluated via Entity Framework 6 (LINQ to Entities) via ODP.NET managed driver (current Version) to the appropriate Oracle statement in order to perform filtering. This works perfectly for string <> nvarchar2 datatypes. The output for a Contains search is something like:
Select *
[...]
FROM "MYSCHEMA"."MYTABLE" "Extent1"
WHERE ("Extent1"."ANVARCHAR2COLUM" LIKE '%givenStrValueToFind%')
Now I want to get the same result for a DateTime <> Timestamp(6) since this line of sql statement is valid for an oracle query and returns all Dates which contains '08':
select * from "MYSCHEMA"."MYTABLE" where ATIMESTAMP6COLUMN like '%08%';
Since I am new to Expression Trees, I first need to know (after googling alot and tried this an that), whether this is possible before I dig deeper into. And if so, how could this be accomplished best? Since there is no Contains Method defined for DateTime and DateTime? Maybe providing Extension methods? And I dont want to execude queries directly against database.
Any hints would be nice to 'unhook' the given database datatype perhaps...
Thx.

For EF 6 you can use :
ctx.MYTABLE.Where(x=>x.ATIMESTAMP6COLUMN.ToString().Contains("08")).ToList();
which translates to
SELECT
[Extent1].[some property name] AS [some property name],
[Extent1].[ATIMESTAMP6COLUMN] AS [ATIMESTAMP6COLUMN],
.
.
.
FROM [dbo].[MYTABLE] AS [Extent1]
WHERE CAST( [Extent1].[ATIMESTAMP6COLUMN] AS nvarchar(max)) LIKE N'%08%'
As far as what I know all versions of EF does not support string functions but EF 6.x supports this kind of functions(The EF that I tested with is EF 6.1.3, the test is done with sql server localdb as DBMS).

I don't know if I understood. Anyway, you don't need to build an expression tree to avoid DB load in memory. LINQ build an expression tree from an expression, EF translates the expression tree to a SQL statement (using the EF Provider) then the query is run on the DB.
In your case the LINQ Query should be something like this
myContext.MYTABLE.Where(e => e.ATIMESTAMP6COLUMN.Contains("08").ToList();
EDIT
Conversions:
You can use .ToString(). It should be a canonical function (function available on every EF Provider).
Other DateTime related functions:
You could have a look to other canonical functions (there are some about dates that allow to retrieve date parts) and also to non canonical functions (functions implemented only in EF Provider for oracle).
References:
Canonical functions https://msdn.microsoft.com/en-us/library/vstudio/bb738626(v=vs.100).aspx
Actually I can't find non canonical functions for Oracle.
If you need it the best thing is that you ask another question.

Related

Difference between lamda where condition and linq where condition?

I am working with MVC Core with EF-6.x and I am using Lambda expression, but my senior told me use LINQ why, because while using lambda with where clause it will pull all the data from database and later it will apply where condition. In case of LINQ if you use where condition it will pull only filtered data. Please let me know what is correct?
e.gLambda: context.tablename.where(condition);// Should I go with this
LINQ: (from T in tablename where t.(condition));// or this?
Please let me know what is correct?
e.gLambda: context.tablename.where(condition);// Should I go with this
LINQ: (from T in tablename where t.(condition));// or this?
Short answer: it doesn't really matter. Since context.tablename ultimately returns an IQueryable<T>, Entityframework will not try to hit the database until you try to iterate the final result from your expression, not to mention, .ToArray() and .ToList() each, does that iteration for you.
Either you used LINQ expression syntax (which gets compiled as LINQ methods) or LINQ methods, when you attempt to begin iterating the results, Entityframework creates an Expression tree for you underneath the hood that consists of your query altogether (including Wheres, Joins, GroupBys, etc). Since the structure of a LINQ might not percisely match the structure of a SQL query (or whatever data-source query), depending on the source (i.e database, e.g SQL Server), Entityframework then attempts to make the best possible optimization to your expression tree so that its structure would match an executable query on the source (e.g SQL Server query). Finally, it translates that expression tree into an actual query and executes it against the data source, and return your data (after doing all the mapping of course).
If you really, and I mean REALLY want to go through the complications of how an IQueryable engine works, I'd suggest taking a walk through Matt Warren's series: 'LINQ: Building an IQueryable provider series'. That's not actually Entityframework but it shares the same concept.
Both syntax will be translated into the same IL code. The difference, if the filter will be applied on server or client side is, if the source is IQueryable<T> or IEnumerable<T>.
my senior told me use LINQ why, because while using lambda with where
clause it will pull all the data from database and later it will apply
where condition.
Your senior is wrong, you can use the statement you prefer they are the same, both will filter the data at database level. If you have Sql Server as database server, you can use Sql Server Profiler to dump the queries executed by both statements and you will see that they are the same.

LINQ: Translating a SQL WITH clause to LINQ and Entity Framework

I have an app using Entity Framework. I want to add a tree view listing products, grouped by their categories. I have an old SQL query that will grab all of the products and categories and arrange them into parent nodes and children. I am trying to translate it into LINQ that uses the EF. But the SQL has a WITH sub-query that I am not familiar with using. I have tried using Linqer and LinqPad to sort it out, but they choke on the WITH clause and I am not sure how to fix it. Is this sort of thing possible in LINQ?
Here is the query:
declare #id int
set #id=0
WITH ChildIDs(id,parentid,type,ChildLevel) AS
(
SELECT id,parentid,type,0 AS ChildLevel
FROM dbo.brooks_product
WHERE id = #id
UNION ALL
SELECT e.id,e.parentid,e.type,ChildLevel + 1
FROM dbo.brooks_product AS e
INNER JOIN ChildIDs AS d
ON e.parentid = d.id
WHERE showitem='yes' AND tribflag=1
)
SELECT ID,parentid,type,ChildLevel
FROM ChildIDs
WHERE type in('product','productchild','productgroup','menu')
ORDER BY ChildLevel, type
OPTION (MAXRECURSION 10);
When I run the query, I get data that looks like this (a few thousand rows, truncated here):
ID.....parentid.....type.....ChildLevel
35429..0............menu.....1
49205..0............menu.....1
49206..49205........menu.....2
169999.49206........product..3
160531.169999.......productchild..4
and so on.
The WITH block is a Common Table Expression, and in this case is used to create a recursive query.
This will be VERY difficult in Linq as Linq doesn't play well with recursion. If you need all of the data on one result set that a Stored Procedure would be easier. Another option is to do the recursion in C# (not in Linq but a recursive function) and do multiple round-trips. The performance will not be as good but if you result set is small it may not make much difference (and you will get a better object model).
You may be able to solve this using LINQ to Entities, but it is non-trivial and I suspect it will be very time consuming.
In situations like this, you may prefer to build a SQL View or Table-Valued Function that returns the results for which you're looking. Then import that View or Table-Valued Function into your EF model and you can pull data directly from it using LINQ.
Querying the View in LINQ is no different than querying a table.
To get data from a Table-Valued Function in LINQ, you pass the function's parameters in after the name of the function, like so:
var query = from tvf in _db.MyTableValuedFunction(parameters)
select tvf;
EDIT
As suggested by #thepirat000, Table-Valued Function support is not available in Entity Framework versions prior to version 5. In order to use this functionality, EF must be running with .NET 4.5 or higher.
At the end of the day, I could not get this to work. I ended up writing out a SQL query dynamically and sending that straight to the database. It works fine, and I am not relying on any direct user input so there is no chance of SQL injection. But it seems so old school! For the rest of my program I am using EF and LINQ.
Thanks for the replies!

Convert SQL statement to NHibernate Query

I tried to ask this question yesterday, but I don't think my wording was very clear.
Therefore, I've tried to reword the question below.
We have an existing system which we are rewriting in MVC4, and we are using NHibernate 3.2 in our new system.
In the old system, we build up a SQL statement similar to this:
SELECT myField as series,
pstatus,
Year(acc_date) AS year,
Month(acc_date) AS month,
COUNT(CAST(reportable AS INT)) AS totalreportable,
SUM(CAST(reportable AS INT)) AS riddorreportable,
SUM(CAST(lt_acc AS INT)) AS losttime,
SUM(CAST(acc_losttime AS INT)) AS totaldayslost,
SUM(CAST(nearmiss AS INT)) AS nearmiss
FROM incident
WHERE 1=1
In the above, we will be replacing "WHERE 1=1" with nHibernate criteria (which we already have in the system to filter data).
myField in the above SQL statement is a field which is selectable by the user e.g. he could choose Department, City etc.
What I need, therefore, is information on how to use nHibernate to achieve the same result as the above SQL statement.
Since you are already using the ICriteria API to construct the WHERE clause, you'll need to use the ICriteria's SetProjection() method in order to build up your dynamic SELECT clause.
This will allow you to use your user's selected field in a dynamic way by using strings.
I was going to write a code example but I felt that someone had already done a very good job of it on this other StackOverflow question: https://stackoverflow.com/a/696020/670028
Official NHibernate documentation on ICriteria Projections: http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection
Chapter 14, 15, 16, and 17 in the documentation in about the different query APIs:
http://nhibernate.info/doc/nh/en/index.html
In addition to those there is also support for LINQ, which nowadays should probably be your preferred query API unless you hit its limitations. If you are building a new system, you should start with NH 3.3.2 to have access to the latest LINQ improvements.
All the query APIs can be made to select (project) different properties based on some user input. I think you may need to be more specific with what you have tried or what problem you experience for a more detailed response.

How to search via Entity Framework on objects and their children?

With Entity Framework 4.3 and Linq, I want to match a search string against certain properties of contained objects and also on the properties of child objects. This turns out to be a rather complex query though, and I'm not sure how to do it. For instance, one property is an integer and I'm not allowed to call .ToString() in a Linq query.
In order to give you an idea of what I'm trying to do, consider this example code:
var dbVersions = from ver in db.Versions
where ver.Name.Contains(search) ||
ver.Children.Any(c=>c.Id.ToString().Contains(search))
select ver;
How should I implement this search? Perhaps via a stored procedure?
The database server is SQL Server 2012.
If you want to use LINQ the framework internally will do the proper optimizations and from my experience the results are quite OK.
If you don't want to use an stored procedure and stick to LINQ keeping it all in your class code use:
SqlFunctions.StringConvert((double)c.Id)
for converting your int to an string. Note that there is no overload for int, so you need to cast it to double or decimal.
In your situation I would suggest using a stored procedure.
If you end up passing one search term which will be used against multiple columns, then your better off writing a stored proc. I once tried something similar to what you're doing, and the end result was really messy LINQ statements that left me feeling dirty :)
Good reference:
x.ToString() is not supported by the entity framework!
Here's an exmaple of how to use stored procs with EF:
http://blogs.msdn.com/b/bindeshv/archive/2008/11/20/using-stored-procedures-in-entity-framework.aspx
Remember to add the stored proc when you "Update Model from database".

ASP.NET MVC Search Page - Integer StartsWith On Linq + EF4

So, in my last post I was asking how to build a dynamic search filter using LINQ and EF4 (See Here) and finally came up with the solution of building the expression as a string and parse it to an expression using the Dynamic LINQ library.
I that solved the problem. I was able to generate a Expression<Func<TSource, out bool>> and pass it to the Where() method of the DbSet. I am also trying to do this using MySql as a database behind EF4.
The problem came when I tried to apply string operations to integers, like searching a database record which consecutive number starts with 1234.
My initial expression was something like: record.ConsecutiveNumber.ToString().StartsWith("1234"). Sadly, as expected, things were not that easy as EF4 fails to query the DbSet with exception:
"LINQ to Entities does not recognize
the method 'System.String ToString()'
method, and this method cannot be
translated into a store expression."
After some Google search I found that this is a common problem. But C'MON! Is there a way to perform a search function that can search records with a consecutive number starting by "1234"?
How pros implement search features with EF4? This is with a single property filter. What if I wanna add multiple filters? God, my head hurts... :/
Thanks!
EDIT:
Thought #1: What about a stored procedure? What about calling a MySql stored procedure from Linq? Am I aiming way too high?
You can use the SqlFunctions.StringConvert method. It requires a double (or decimal) so you'll have to cast your int ConsecutiveNumber.
Replace:
record.ConsecutiveNumber.ToString().StartsWith("1234")
With:
SqlFunctions.StringConvert((double)record.ConsecutiveNumber).StartsWith("1234")
Have you looked at the Dynamic LinQ Library:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
And for your question
How to use "contains" or "like" in a dynamic linq query?
Previously I have gotten the code for this lib and just taken a look inside, it is pretty easy to follow.
This would be my thought process on getting it to work. Hopefully it points you in the right direction.
According to other posts SqlFunctions.StringConvert((double)record.ConsecutiveNumber) works for Sql Server.
Problem with converting int to string in Linq to entities
And here is relevant information on linq conversions.
Linq int to string
And here is an answer hinting at writing your own sql function for stringconvert
Using a SQL Function in Entity Framework Select
If SqlFunctions.StringConvert doesn't work for you I'd suggest looking at figuring out how to do it in Sql and then writing your own [EdmFunction()] attribute based method.
I haven't got a clue if this will work over Linq to EF or not but presuming that they mapped the Math operations, this might solve your need:
record.ConsecutiveNumber / Math.Pow(10, Math.Truncate(Math.Log10(record.ConsecutiveNumber) - 3)) == 1234
This is basically dividing the number by a power of 10 just big enough to leave the first 4 digits.
I know this is very hacky and inefficient even if it works, but there you go. :)
Any method calls in a LINQ to Entities query that are not explicitly mapped to a canonical function will result in a runtime NotSupportedException exception being thrown.
Check mapping canonical function here:
http://msdn.microsoft.com/en-us/library/bb738681.aspx
In this case, you can use Math function. (I don't think code first can use in product project at that time)

Categories

Resources