How to make a simple search function in linq and EF - c#

I want to simply search a database for a certain string, how can i accomplish this using linq and EF (if using these tools for it are not practical I am open to any suggestions). I just want to take a string and search my usernames, the search should be able to handle things only parts of the username (using some sort of 'contains' function)

The basics of what you are asking is..
var found = MyContext.Users.Where(user => user.UserName.Contains(searchString));
You would need to substitute actual entity names/values for the example code posted.

Related

Return Values That Are In Lowercase

We recently discovered a bug in our system whereby any serial numbers that have been entered in lowercase have not been processed correctly.
To correct this, we need to add a one off function that will run through the database and re-process all items with lower case serial numbers.
In linq, is there a query I can run that will return a list of such items?
Note: I am not asking how to convert lowercase to uppercase or reverse, which is all google will return. I need to generate a list of all database entries where the serial number has been entered in lowercase.
EDIT: I am using Linq to MS SQL, which appears to be case insensitive.
Yes, there is. You can try something like this:
var result = serialnumber.Any(c => char.IsLower(c));
[EDIT]
Well, in case of Linq to Entities...
As is stated here: Regex in Linq (EntityFramework), String processing in database, there's few ways to workaround it.
Change database table structure. E.g. create table Foo_Filter which will link your entities to filters. And then create table Filters
which will contain filters data.
Execute query in memory and use Linq to Objects. This option will be slow, because you have to fetch all data from database to memory
Note: link to MSDN documentation has been added by me.
For example:
var result = context.Serials.ToList().Where(sn => sn.Any(c => char.IsLower(c)));
Another way is to use SqlMethods.Like Method
Finally, i'd strongly recommend to read this: Case sensitive search using Entity Framework and Custom Annotation

Entity framework and linq string comparsion issue

I have a problem with linq..
lets see the code
I have an article class:
public calss Article
{
public string Tag{get; set; }
}
I save each tag for article splitted by , comma.
for example : first,second,third
and when I want to get an article I want to get articles that has any common tag.
I use this query but:
var relatedArticles =
_db.Articles.Where(a => a.Tag
.Split('،')
.Any(t => article.Tag
.Split('،')
.Any(ac => ac == t)));
and I am getting this exception:
LINQ to Entities does not recognize the method 'System.String[]
Split(Char[])' method
Any other way?
Update:
i cant keep tags in different table because i must let user to create tags as many as he wants when he/she is inserting article.
like 50 and it will be overhead to check if that tag exists or not when saving article to db.
Set your class as follows:
public class Article
{
public List<string> Tag{get; set; }
}
I'm not 100% sure what your 2nd statement does, but you can use a.Tag.Contains() to check your values.
I think my comment could be worth as answer to your problem, so i write it down as one :)
You should think about your table / class design.
You need to normalize it because that looks like n:m reference. Keep the article in one table with a reference to a mapping table, where you reference the arcticleId and the tagId and than one table with that tags with a primary key tagId.
If one Tag will change in future, you don't need to update every article, you just update that particular tag and it changes for every article.
The "a.Tag.Split('،')" is a node in the expression tree that your IQueryable is, not an actual operation. When you materialize results by calling something like ToList, the whole expression tree is translated into SQL expression before execution - this is the point of error because translator doesnt have an idea how to convert Split() method into sql statement.
As an alternative, you can retrieve all results into app, materialize them by ToList() and then do what you want with them as IEnumerables. Also, you can write a stored procedure and pass search tags array into there.
Also, maybe it will work - try to pass a simple values array (not as methods) into query so resulting sql looks like
"WHERE ... IN ...".
it means that Linq to entities failed to find translation of split method that can be written as SQL query. if you want to perform split functions you have to bring the record in memory by calling ToList(), AsEnumerable() etc.
But better approach would be to create separate table for tags in your db.
Linq query would look something like this(supposing many-to-many relationship between articles and tags):
var relatedArticles =
_db.Articles.Where(a => a.Tags.Any(t => t.Articles.Count() > 1));
// if Article has Tag which is assigned more then to one Article then it suits us
You can't call regular methods like string.Split() directly in Linq when working with EF, since it can't be translated to SQL.
You could append AsEnumerable() to your Where() clause to cause Linq to fetch the data, allowing you to perform operations like that on it later. Unfortunately, that will not permit you to do what you want with the list without fetching the whole list, which I'm sure you would rather avoid.
Perhaps you could do something like this instead?:
List<string> tagsForCurrentArticle = ... // fetch this first somehow
_db.Articles.Where(a =>
tagsForCurrentArticle.Any(tag =>
a.Tag.Contains(tag)))
Note, just to be clear: This should work, but the better option, if possible, would be to move your tags out into a separate table, as others have suggested.

Dynamically adding select fields using LINQ lambda

Lets say we have an expression:
var prices = from p in PriceDB.Prices
where p.TypeID == 12
orderby p.PriceType.Title
select p;
Is it possible to modify the select list?
I imagine it looking something like this:
var newPriceList = prices.Select( p => p.ExchangeRate );
This may be an odd request, but in my code (which is too long and complex to post here) I want to conditionally add fields to be output depending on a CheckBoxList.
I assume, of course, that I'm trying to go about this the wrong way...
I imagine it looking something like this:
Actually it would look exactly like that. First, build a query, selecting the entire record. Then add a select (using the Select() method seem the easiest way) to limit the selection. Linq-to-Sql will sort out the two selects, and use the proper reselt, so theres just one select in the final SQL.
There's no really good way to choose between multiple selects. I would probably use a switch/case.
While you could go down the dynamic route, I would strongly consider not doing so. What is the cost of fetching the extra values if you don't need them, in your particular case? Is the problem that they're being displayed dynamically and you only want them displayed in certain cases? If so, I'd suggest modifying the display code somehow.
It's hard to stay strongly typed (which has various advantages) while being dynamic in terms of what you fetch. Of course, if you always want to fetch the same "shape" of data (e.g. always just a decimal value from each row) then that's reasonably easy - let me know if that's something you'd like to see demonstrated.
If you could tell us more about your problem, we may be able to suggest alternative solutions.
If I understood you correct this is explaining how to build dynamic queries:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You might want to look at this Dynamic LINQ and Dynamic Lambda expressions?
Or the Dynamic Expression API (System.Linq.Dynamic).

How to build a LINQ query from text at runtime?

I have a
class A {
public int X;
public double Y;
public string Z;
// and more fields/properties ...
};
and a List<A> data and can build a linq query like e.g.
var q = from a in data where a.X > 20 select new {a.Y, a.Z};
Then dataGridView1.DataSource = q.ToList(); displays the selection in my DataGridView.
Now the question, is it possible to build the query from a text the user has entered at runtime? Like
var q = QueryFromText("from a in data where a.X > 20 select new {a.Y, a.Z}");
The point being, that the user (having programming skills) can dynamically and freely select the displayed data.
Dynamic Linq baby!
r.e. comment.
Yes, the example as written may not be possible using Dynamic Linq, but if you factor out the constants, e.g. 'from a in data' you are left with a 'where' and a 'select' which can be expressed with dynamic linq.
so two text boxes, maybe three if you include an orderby, could possibly satisfy your requirements.
Just a thought.
Jon has an interesting approach but i would be leery of compiling and executing unrestrained code.
Well, you can use CSharpCodeProvider to compile code at execution time. Have a look at Snippy for an example of this. In this case you'd need to compile the user code in a method which accepts a List<A> called data. My experience is that it works, but it can be slightly fiddly to get right - particularly in terms of adding the appropriate references etc.
Answering it pretty late; though, it will help someone who visits this page.
I had similar requirement and I solved it by dynamically compiling string as LINQ query, executing it over in-memory collection and collecting the result. Only catch is user input needs to be valid C# compile-able code else it returns an exception message instead of result.
Code is pretty long so here is the github link
Sample application on github shows multiple examples including projection.
Although there may be some ways to do this, LINQ simply isn't designed for this scenario. Using CodeDOM (as Jon suggested) is probably the only way to get that easily done. If you trust the user and he/she has programming skills, you could perhaps just use old fashioned methods and let the user enter the query using SQL?
If you, on the other hand, choose to create some visual tool for constructing queries, you don't need to build them by composing strings and you can compose expression trees instead. For example using Linq Kit and AsExpandable.
check out this library
http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Converting user-entered search query to where clause for use in SQL Server full-text search

What's the best way to convert search terms entered by a user, into a query that can be used in a where clause for full-text searching to query a table and get back relevant results? For example, the following query entered by the user:
+"e-mail" +attachment -"word document" -"e-learning"
Should translate into something like:
SELECT * FROM MyTable WHERE (CONTAINS(*, '"e-mail"')) AND (CONTAINS(*, '"attachment"')) AND (NOT CONTAINS(*, '"word document"')) AND (NOT CONTAINS(*, '"e-learning"'))
I'm using a query parser class at the moment, which parses the query entered by users into tokens using a regular expression, and then constructs the where clause from the tokens.
However, given that this is probably a common requirement by a lot of systems using full-text search, I'm curious as to how other developers have approached this problem, and whether there's a better way of doing things.
How to implement the accepted answer using .Net / C# / Entity Framework...
Install Irony using nuget.
Add the sample class from:
http://irony.codeplex.com/SourceControl/latest#Irony.Samples/FullTextSearchQueryConverter/SearchGrammar.cs
Write code like this to convert the user-entered string to a query.
var grammar = new Irony.Samples.FullTextSearch.SearchGrammar();
var parser = new Irony.Parsing.Parser(grammar);
var parseTree = parser.Parse(userEnteredSearchString);
string query = Irony.Samples.FullTextSearch.SearchGrammar.ConvertQuery(parseTree.Root);
Perhaps write a stored procedure like this:
create procedure [dbo].[SearchLivingFish]
#Query nvarchar(2000)
as
select *
from Fish
inner join containstable(Fish, *, #Query, 100) as ft
on ft.[Key] = FishId
where IsLiving = 1
order by rank desc
Run the query.
var fishes = db.SearchLivingFish(query);
This may not be exactly what you are looking for but it may offer you some further ideas.
http://www.sqlservercentral.com/articles/Full-Text+Search+(2008)/64248/
In addition to #franzo's answer above you probably also want to change the default stop word behaviour in SQL. Otherwise queries containing single digit numbers (or other stop words) will not return any results.
Either disable stop words, create your own stop word list and/or set noise words to be transformed as explained in SQL 2008: Turn off Stop Words for Full Text Search Query
To view the system list of (English) sql stop words, run:
select * from sys.fulltext_system_stopwords where language_id = 1033
I realize it's a bit of a side-step from your original question, but have you considered moving away from SQL fulltext indexes and using something like Lucene/Solr instead?
The easiest way to do this is to use dynamic SQL (I know, insert security issues here) and break the phrase into a correctly formatted string.
You can use a function to break the phrase into a table variable that you can use to create the new string.
A combination of GoldParser and Calitha should sort you out here.
This article: http://www.15seconds.com/issue/070719.htm has a googleToSql class as well, which does some of the translation for you.

Categories