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

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)

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.

How to get a correct result of binary string intersection in Entity to Linq query

I save my data in a binary-look string, "100010" ,for example. And I want to check whether it has same value in corresponding place with the other string "100000".
So I try to use "Intersection". In this Condition, the result of intersection will be "100000", and it could be seen as the item I need for my requirement. But how can I use this conception when I query a Entity to Linq statement?
Here is my thought:
var chemicals = db.ChemicalItem.Where(c => c.CategoryNumber.ToCharArray().Intersect(catekey.ToCharArray()).Count()>0);
"CategoryNumber" is my data, and "catekey" is the string for comparing. Both of them are binary-look string(cantain 6 chars). And if the count is not 0,they have '1's in the same index. And I can get the correct query.
Sadly, It didn't work. I always get DbExpressionBinding Error. Can somone tell me What's Wrong? Thanks.
PS:I'm not good at English and post the question here first time, sorry for my bad expression and thank for your reading.
LINQ to Entities is trying to create a SQL query out of your condition, but is not able to do it for the expression you specified.
One way to "fix" the problem would be to do the filtering in code instead of in SQL, but this will impact performance, because all of the records will be retrieved to the client and filtered there. This is how you could do it (notice the added ToList()):
var chemicals = db.ChemicalItem.ToList().Where(c => c.CategoryNumber.ToCharArray().Intersect(catekey.ToCharArray()).Count()>0);
A suggested way would be to do the filtering in SQL, but in this case you will need to write an equivalent stored procedure in SQL which will do the filtering and call that from your EF code. Still such filtering will not be very effective because SQL will not be able to use any indices and will always need to do a table scan.

Use a NaturalSortComparer in a LINQ Where Clause

Say I have a table Table1 with a string field [ProductString] with values:
Alpha, alphanumeric or numeric: eg ABC, B4, U2, C 5, 100, U1, U5, U6, U11
I want to be able to take a where clause like "ProductString >= U5", and pass this to a LINQ statement as a string so it evaluates
Table1.Where(t=> t.ProductString >= 'U5');
Normally this would return results U5 and U6.
However, this I want to be able to use a NaturalSortComparer somehow so that the results returned are U5, U6 and U11.
I know how to use the comparer in an OrderBy, by I wanted to be able to use it at the Where stage.
Using natural sort comparer:
var comparer = new NaturalComparer();
Table1.Where(t=>
comparer.Compare(t.ProductString, "U5") >= 0);
Presuming all your product strings is on the format U%number% then why not abuse that fact?
Table1.Where(t=> int.Parse(t.ProductString.Replace("U","")) >= 5);
If you're using LINQ to Entities I'm not certain this will compile to a store expression (i.e that SQL knows what to do with this - I guess it should).
I'm a little confused, given the accepted answer, about whether this question relates to LINQ to Entities or not. The accepted answer doesn't appear to be a solution that would work in the LINQ to Entities context, but the comments on the question by the OP seem to confirm that this is being executed in the database context. Anyway, this answer is specifically targeted toward LINQ to Entities.
I think doing this in SQL Server would be hard, but not impossible. The problem is that .NET knows what NaturalSortComparer is, but SQL Server (where you want the query to ultimately take place) has no such concept. The best idea I can think of would consist of 2 parts:
Create a UDF (User Defined Function) in SQL server that will give a product that is orderable via natural sort: CREATE FUNCTION Naturalize(#val as nvarchar(max)) RETURNS nvarchar(1000). There's a pretty cool answer here that creates a UDF wrapper around a CLR function to accomplish just that.
Next create a function mapping for your DbContext that maps the UDF above to a function that can be called inside an EF query against the DbContext. Something like this:
[DbFunction("MyContext", "Naturalize")]
public static string Naturalize(this string value)
{
throw new NotSupportedException("This function can only be invoked from LINQ to Entities.");
}
Once you've got these two pieces in place, you can readily use this new function inside an entity query to compare strings using the Naturalized value in the comparison:
Table1.Where(t=> t.ProductString.Naturalize() >= "U5".Naturalize());
Bear in mind that the UDF will be executed against every row contained in the query, which is the whole table in the above example. You'll want to make sure to pare down your query to something manageable before applying the function as a sub-query. Or you may want to try applying some type of UDF-based index on the table in question.
If you are going to be doing searches like this a lot, then what will be the best thing to do is add two new fields to your table, [ProductCode] & [ProductNumber] which separate the two parts of the [ProductString].
Then you comparison becomes:
Table1.Where(t=> t.ProductCode == "U" && t.ProductNumer > 5);

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".

NHibernate - Equivalent of CountDistinct projection using LINQ

I'm in the midst of trying to replace a the Criteria queries I'm using for a multi-field search page with LINQ queries using the new LINQ provider. However, I'm running into a problem getting record counts so that I can implement paging. I'm trying to achieve a result
equivalent to that produced by a CountDistinct projection from the Criteria API using LINQ. Is there a way to do this?
The Distinct() method provided by LINQ doesn't seem to behave the way I would expect, and appending ".Distinct().Count()" to the end of a LINQ query grouped by the field I want a distinct count of (an integer ID column) seems to return a non-distinct count of those values.
I can provide the code I'm using if needed, but since there are so many fields, it's
pretty long, so I didn't want to crowd the post if it wasn't needed.
Thanks!
I figured out a way to do this, though it may not be optimal in all situations. Just doing a .Distinct() on the LINQ query does, in fact, produce a "distinct" in the resulting SQL query when used without .Count(). If I cause the query to be enumerated by using .Distinct().ToList() and then use the .Count() method on the resulting in-memory collection, I get the result I want.
This is not exactly equivalent to what I was originally doing with the Criteria query, since the counting is actually being done in the application code, and the entire list of IDs must be sent from the DB to the application. In my case, though, given the small number of distinct IDs, I think it will work, and won't be too much of a performance bottleneck.
I do hope, however, that a true CountDistinct() LINQ operation will be implemented in the future.
You could try selecting the column you want a distinct count of first. It would look something like: Select(p => p.id).Distinct().Count(). As it stands, you're distincting the entire object, which will compare the reference of the object and not the actual values.

Categories

Resources