DBSet and dynamic sql expressions - linq

So I have Products class that represent the products table.
To get all the records I do:
db.Products.ToList()
And I have a string like this:
String queryString = "mp=5 AND optic=TRUE AND price=500";
My question is how can I use this string to filter Products? Where func only accept lambda expressions..
Thanks

I'm not sure if it's still supported or not, but you can use Dynamic LINQ to allow you to add 'text' based expressions as you require. See:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://pranayamr.blogspot.com/2011/04/dynamic-query-with-linq.html
You may also want to think about using a Predicate builder to do the same job more declaratively. There are a few out there, but one that I've used with great success is the albahari one:
http://www.albahari.com/nutshell/predicatebuilder.aspx
hope this helps..

You can execute Raw SQL against the DbSet and return a strong typed list. For detail, please refer to this blog post by EF team.

Related

How to do string functions on a db table column?

I am trying to do string replace on entries of a column inside a db table. So far, I have reached till here:
$misa = DB::table('mis')->pluck('name');
for($i=0;;$i++)
{
$misa[$i] = substr_replace("$misa[$i]","",-3);
}
The error I am getting is "Undefined offset:443".
P.S. I am not a full-fledged programmer. Only trying to develop a few simple programs for my business. Thank You.
Since it's a collection, use the transform() collection method transform it and avoid this kind of errors. Also, you can just use str_before() method to transform each string:
$misa = DB::table('mis')->pluck('name');
$misa->transform(function($i) {
return str_before($i, ':ut');
});
There are a few ways to make this query prettier and FASTER! The beauty of Laravel is that we have the use of both Eloquent for pretty queries and then Collections to manage the data in a user friendly way. So, first lets clean up the query. You can instead use a DB::Raw select and do all of the string replacing in the query itself like so:
$misa = DB::table('mis')->select(DB::raw("REPLACE(name, ':ut' , '') as name"));
Now, we have a collection containing only the name column, and you've removed ':ut' in your specific case and simply replaced it with an empty string all within the MySQL query itself.
Surprise! That's it. No further php manipulation is required making this process much faster (will be noticeable in large data sets - trust me).
Cheers!

How to perform a NOT query with postgres_ext

Is it possible to perform a NOT type query with chained methods using postgres_ext?
rules = Rule.where.overlap(:tags => ["foo"])
Basically want the inverse of the above. Thanks!
In regular active record you can use .where.not as described in this article: https://robots.thoughtbot.com/activerecords-wherenot however looking through the source code of postgres_ext I don't know if it is defined in that library. You may be able to construct your query in a way that uses the native active record methods.

How to use SQL function in reference in NHibernate?

I'm using Fluent NHibernate on Oracle and my problem is I have to apply lower() function on every string in where conditions. I made my own dialect that instead Oracle lower function is being used nls_lower. Database is primarly used by Microsoft Dynamics AX and this function improve performance. In standard query like this everything works fine:
session.QueryOver<User>()
.Where(x => x.Name.lower() == userName.lower())
.SingleOrDefualt<User>();
But how can I apply this lower() function in references? I can't find anything suitable for this and I expect It can be done somehow. I would expect something like this in mapping class but I can't find it:
References<Settings>(x => x.Settings)
.Column("SettingId").lower();
I don't want to convert my string immediately to lowercase but I really need generate query like this:
select * from User where nls_lower(Name) == nls_lower("somename");
Thank you!
nls_lower is not a registered function in the Oracle dialect.
You can have a look in the code base in the Oracle8iDialect class.
In this situation you have to register your own extension. Have a look here.
When you've registered your dialect extension you should be able to call it this way:
var filter1 = Restrictions.Eq(
Projections.SqlFunction("nls_lower", NHibernateUtil.String,
Projections.Property<User>(x => x.Name)), userName.ToLower());
var user = session.QueryOver<User>();
user.Where(myFilter)
.SingleOrDefualt<User>();
You can define custom SQL to load entities. See here.

OrderBy("it." + sort) -- Hard coding in LINQ to Entity framework?

I have been trying to use dynamic LINQ to Entity in my application for specifying the OrderBy attribute at runtime. However when using the code as described in the majority of documentation:
var query = context.Customer.OrderBy("Name");
I received the following exception:
System.Data.EntitySqlException: 'Name' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly.
After much searching I found this MSDN page:
http://msdn.microsoft.com/en-us/library/bb358828.aspx
Which included the following code example:
ObjectQuery<Product> productQuery2 = productQuery1.OrderBy("it.ProductID");
This prompted me to change my code to the following:
var query = context.Customer.OrderBy("it.Name");
After this the code works perfectly. Would anyone be able to confirm that this is indeed the correct way to get OrderBy working with LINQ to Entity? I can’t believe that the framework would have been implemented in this way, perhaps I have overlooked something?
Thanks, Matt
The it.Name syntax is ESQL and is indeed specific to the EF. There are good reasons to use this sometimes (e.g., collation specifiers), but it's not what I normally do.
Usually I use standard LINQ expressions:
var query = context.Customer.OrderBy(p => p.Name);
You can also use System.Linq.Dynamic, if you download it from Code Gallery, and then your original query:
var query = context.Customer.OrderBy("Name");
...will work.
No nice way, so far
My answer to this question was to create a stored procedure which has parameter to control sorting.

LINQ multiple where clause

I have a course table which I need to search based on keywords typed in the search box.
Here is a sample query:
SELECT * FROM Courses WHERE
Title LIKE '%word%' OR Title LIKE '%excel%' OR
Contents LIKE '%word%' OR Contents LIKE '%excel%'
How can I convert this in LINQ where LINQ would dynamically generate WHERE statements based on each keywords.
I tried to user PredicateBuilder it works fine as long as the field is VARCHAR. For the "TEXT" fields the quotes are not generated thus causing compiler to give an error message. Here is the SQL generated by PredicateBuilder
SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active],
FROM [dbo].[Courses] AS [t0]
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%)
Notice there is no single Quote for the "Contents" field which is a Text field in the database.
Is there any easy way to build WHERE statement and attach it with query? Does anyone know how I can do this without PredicateBuilder?
Thanks in advance.
Since you are working w/ LINQ I suppose you are working against a LINQ-to-SQL data context right? I don't have a spare DataContext lying around to test this, but this should give you some ideas.
I don't know if it will work against data context though, but most of these are pretty basic stuff (chaining OR operator and Contains method call) so it shouldn't cause problem when the query translates to SQL.
First I create a custom function that would build my predicate:
Func<string, Func<DataItem, bool>> buildKeywordPredicate =
keyword =>
x => x.Title.Contains(keyword)
|| x.Contents.Contains(keyword);
This is a function which takes a single string keyword and then return another function which takes a DataItem and checks it against the keyword.
Basically, if you pass in "Stack", you'll get a predicate: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack").
Next, since there are many possible keywords and you need to chain it with an OR operation, I create another helper function to chain 2 predicates together with an OR
Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
(pred1, pred2) =>
x => pred1(x) || pred2(x);
This function takes 2 predicates and then join them up with an OR operation.
Having those 2 functions, I can then build my where predicate like this:
foreach (var word in keywords) {
filter = filter == null
? buildKeywordPredicate(word)
: buildOrPredicate(filter, buildKeywordPredicate(word));
}
The first line inside the loop basically checks if the filter is null. If it is, then we want a simple keyword filter built for us.
Else if the filter is not null, we need to chain existing filters with an OR operation, so we pass the existing filter and a new keyword filter to buildOrPredicate to do just that.
And then we can now create the WHERE part of the query:
var result = data.Where(filter);
Passing in the complicated predicate we've just built.
I don't know if this will different from using PredicateBuilder but since we are deferring query translation to the LINQ-to-SQL engine, there should not be any problems.
But as I said, I havn't tested it against a real data context, so if there's any problems you can write in the comments.
Here's the console app that I built to test: http://pastebin.com/feb8cc1e
Hope this helps!
EDIT: For a more generic and reusable version which involves properly utilizing the Expression Trees in LINQ, check out Thomas Petricek's blog post: http://tomasp.net/articles/dynamic-linq-queries.aspx
As predicate builder doesn't know the DB type of the property the Contains method is called on, I guess this might be a problem inside linq to sql. Have you tried with a normal query (not with predicate builder) and a TEXT column with Contains?

Resources