How do i find out if a string is containing the exact word i am looking for?
example: "this is my text"; word looking for: "text"; found: yes.
example: "these are my texts"; word looking for: "text"; found: no.
it's inside a linq to entities query, so regex won't work?
Edit:
This is more or less what i'm doing now and i want to replace it by a function that returns only when it's the exact match.
using (Model.Manager ctx = new Model.Manager())
{
var result = from p in ctx.Companies where p.Name.Contains(workLookingFor) select p;
}
Solution so far:
I could use .Contains() on my DB and use RegEx on the results pulled from the DB. Since the exact matches are always inside the broader results from .Contains() (which i still need anyways) this could be a good solution
This works for me. It's not perfect but might help.
public static bool matchWholeWord(string test, string search)
{
var index = test.IndexOf(search);
if (index == -1)
return false;
var after = index + search.Length;
if (after == test.Length)
return true;
return !char.IsLetterOrDigit(test[after]);
}
in your code:
using (Model.Manager ctx = new Model.Manager())
{
var result = from p in ctx.Companies
where matchWholeWord(p.Name, workLookingFor)
select p;
}
There isn't an easy way. You have three options
run your query, then do the pattern matching on the client
use SQL Fulltext Search engine
add a CLR function to the database that lets you do regex matching
I had to use something similar to this to implement a search algorithm using LINQ recently. I found the MSDN article on combining LINQ and Regular Expressions to be useful, along with a regular expression that used the space marker to identify whitespace. By constructing the regex with my search parameters and combining that into my LINQ expression, I ended up with what I needed.
Related
I am using the latest version of Mongo C# driver which uses a lot of Async and builder pattern. Which is nice. I am trying to convert SQL where clauses into Mongo FilterDefinition object.
Any idea how to handle "contains"?
like:
where x contains 'ABC'
In order to achieve that in V2 API, use the `Filter.Regex':
var collection = db.GetCollection<BsonDocument>("collection");
var filter = Builders<BsonDocument>.Filter.Regex("fieldName", new BsonRegularExpression(".*fieldValue.*"));
var data = await (await coll.FindAsync<BsonDocument>(filter).ConfigureAwait(false)).ToListAsync();
//continue process data
If x is a string, you could do so with a simple regex. For the 2.0 driver, you can manually create the FilterDefinition:
FilterDefinition<BsonDocument> filter = "{ x : { $regex : /ABC/ } }";
Or build the filter use the Builder:
var builder = Builders<BsonDocument>.Filter;
var filter = builder.Matches("x", "ABC");
Then you can use the filter in your query:
using (var cursor = await collection.Find(filter).ToCursorAsync())
{
// ...
}
I was able to get this working using Filter.AnyIn like so
var filter = Builders<BsonDocument>.Filter.AnyIn("x", new List<string> { "ABC" });
This works if you're looking for multiple values too, just add them to the list.
First, I highly recommend taking MongoDB University's .NET course (from Mongo itself). It's really thorough, and covers your question (and more) in depth.
Second, I assume that x is an array in your example.
MongoDB correctly handles polymorphism with arrays. If you have a class Post with an array of Tags, you can filter where Tag = ABC.
If you're using the C# linq methods, that looks like .Find(p => p.Tags == "ABC"). If you're using BsonDocument, that looks like new BsonDocument().Add("Tags", "ABC").
I have another way which I don't love but it works. The answer that is marked correct is half wrong (Matches is a method of Builders). In this example the / act like a % in a sql query LIKE statement. I'm still looking for a better way and will update if I find one that is more Equals filter below.
List<yourobject> someList = await collection.Find("{ x: /Test/ }").ToListAsync();
var filter = Builders<yourobject>.Filter.Eq("x", "ABC");
List<yourobject> someList = await collection.Find(filter).ToListAsync();
If you want to just search input text you need to replace regex special characters.
Regex.Escape will ensure that these characters are processed literally rather than as metacharacters. Otherwise input text can be used to query regex patterns which is probably not what is required.
var text = "ABC";
var filter = Builders<BsonDocument>.Filter.Regex("x", BsonRegularExpression.Create(Regex.Escape(text)));
If you need case insensitive check. Then you can pass case insensitive regex to BsonRegularExpression.Create:
var text = "ABC";
var escapeText = Regex.Escape(text);
var regex = new Regex(escapeText, RegexOptions.IgnoreCase);
var filter = Builders<BsonDocument>.Filter.Regex("x", BsonRegularExpression.Create(regex));
I sum myself to the hapless lot that fumbles with custom methods in LINQ to EF queries. I've skimmed the web trying to detect a pattern to what makes a custom method LINQ-friendly, and while every source says that the method must be translatable into a T-SQL query, the applications seem very diverse. So, I'll post my code here and hopefully a generous SO denizen can tell me what I'm doing wrong and why.
The Code
public IEnumerable<WordIndexModel> GetWordIndex(int transid)
{
return (from trindex in context.transIndexes
let trueWord = IsWord(trindex)
join trans in context.Transcripts on trindex.transLineUID equals trans.UID
group new { trindex, trans } by new { TrueWord = trueWord, trindex.transID } into grouped
orderby grouped.Key.word
where grouped.Key.transID == transid
select new WordIndexModel
{
Word = TrueWord,
Instances = grouped.Select(test => test.trans).Distinct()
});
}
public string IsWord(transIndex trindex)
{
Match m = Regex.Match(trindex.word, #"^[a-z]+(\w*[-]*)*",
RegexOptions.IgnoreCase);
return m.Value;
}
With the above code I access a table, transIndex that is essentially a word index of culled from various user documents. The problem is that not all entries are actually words. Nubers, and even underscore lines, such as, ___________,, are saved as well.
The Problem
I'd like to keep only the words that my custom method IsWord returns (at the present time I have not actually developed the parsing mechanism). But as the IsWord function shows it will return a string.
So, using let I introduce my custom method into the query and use it as a grouping parameter, the is selectable into my object. Upon execution I get the omninous:
LINQ to Entities does not recognize the method
'System.String IsWord(transIndex)' method, and this
method cannot be translated into a store expression."
I also need to make sure that only records that match the IsWord condition are returned.
Any ideas?
It is saying it does not understand your IsWord method in terms of how to translate it to SQL.
Frankly it does not do much anyway, why not replace it with
return (from trindex in context.transIndexes
let trueWord = trindex.word
join trans in context.Transcripts on trindex.transLineUID equals trans.UID
group new { trindex, trans } by new { TrueWord = trueWord, trindex.transID } into grouped
orderby grouped.Key.word
where grouped.Key.transID == transid
select new WordIndexModel
{
Word = TrueWord,
Instances = grouped.Select(test => test.trans).Distinct()
});
What methods can EF translate into SQL, i can't give you a list, but it can never translate a straight forward method you have written. But their are some built in ones that it understands, like MyArray.Contains(x) for example, it can turn this into something like
...
WHERE Field IN (ArrItem1,ArrItem2,ArrItem3)
If you want to write a linq compatible method then you need to create an expresion tree that EF can understand and turn into SQL.
This is where things star to bend my mind a little but this article may help http://blogs.msdn.com/b/csharpfaq/archive/2009/09/14/generating-dynamic-methods-with-expression-trees-in-visual-studio-2010.aspx.
If the percentage of bad records in return is not large, you could consider enumerate the result set first, and then apply the processing / filtering?
var query = (from trindex in context.transIndexes
...
select new WordIndexModel
{
Word,
Instances = grouped.Select(test => test.trans).Distinct()
});
var result = query.ToList().Where(word => IsTrueWord(word));
return result;
If the number of records is too high to enumerate, consider doing the check in a view or stored procedure. That will help with speed and keep the code clean.
But of course, using stored procedures has disadvatages of reusability and maintainbility (because of no refactoring tools).
Also, check out another answer which seems to be similar to this one: https://stackoverflow.com/a/10485624/3481183
public ActionResult GenerateReport(FormCollection Form)
{
var type_id = Form["type_id"];
var Start_Date = Form["Start_Date"];
StringBuilder sb = new StringBuilder();
sb.Append("db.contracts.Where(");
if (!type_id.Equals(null))
{
sb.Append("a => a.type_id == type_id");
}
if (!Start_Date.Equals(null))
{
sb.Append("&& a => a.Start_Date == Start_Date");
}
sb.Append(");");
//here I need to run the query!!
return View(cm);
}
How can i execute this LINQ query in C#,
I just want to run the query and get the results..
Please help me...
Thanks in Advance...
EDIT: this answer works with the original question content, how to execute this LINQ expression from a string:
var expression = #"( from a in Assignments
where a.assignmentID == 1 && a.assignmentID == 4 )
select new AssignmentModel
{
Title = a.Title,
Description = a.Description
}).ToList()";
though this answer should work with the generated string in the current question, only you would be injecting db.contracts rather than Assignments as I explain below.
The alternative to using the compilation classes as #GekaLlaur suggests is to compile the string into an Expression tree, which is possibly more appropriate here as you're compiling LINQ expressions.
The solution found in this SO post (Chosen Solution) looks as though it should work out of the box for you, only using var p = Expression.Parameter(typeof(List<AssignmentModel>), "Assignments"); to describe your parameter. I would test it with your specific example but I don't already have the libraries (linked here).
Don't do this. Use a Predicate Builder instead!
Here is a great implementation from C# in a nutshell:
http://www.albahari.com/nutshell/predicatebuilder.aspx
The predicate builder uses a free library called linqkit:
http://www.albahari.com/nutshell/linqkit.aspx
Here is another SO question that addresses this topic and how the whole thing works
How does PredicateBuilder work
I have a list of strings. I need to be able to filter them in a similar way to a Google query.
Ex: NOT water OR (ice AND "fruit juice")
Meaning return strings that do not have the word water or return strings that can have water if they have ice and "fruit juice".
Is there a mechanism in .NET that can allow the user to write queries in this form (say in a textbox) and given a List or IEnumerable of string, return the ones that contain this.
Can LINQ maybe do something like this?
I am aware that I can do this with LINQ, I'm more concerned with parsing an arbitrary string into an executable expression.
There is nothing built in.
You will need to parse such a string yourself and possibly use the Expression classes to build up an executable expression from which to filter.
For this query: Meaning return strings that do not have the word water or return strings that can have water if they have ice and "fruit juice".
Try something like this if you are going to use LINQ
yourList.Where(i => !i.Contains("water") ||
(i.Contains("water") &&
i.Contains("ice") &&
i.Contains("fruit juice")));
I think we can't answer you using a code sample since as you said this is more logical.
what I would do in such a scenario is to have predefined conditions (saved somewhere) which will contain all the conditions you need along with their "coding translations" like:
and
or
and not
and or
etc...
and what you will do at runtime is to translate these conditions/criteria into sql or linq or whatever language you need to pass it to.
In LINQ: list.Where(item => !item.Contains("water") || (item.Contains("ice") && item.Contains("fruit juice")))
You can try to use the DataTable.Select method:
public static class ExpressionExtensions {
public static IEnumerable<T> Select<T>(this IEnumerable<T> self, string expression) {
var table = new DataTable();
table.Columns.Add("Value", typeof(T));
foreach (var item in self) {
var row = table.NewRow();
row["Value"] = item;
table.Rows.Add(item);
}
return table.Select(expression).Select(row => (T)row["Value"]);
}
}
But you have to follow its format to create your expression:
var filtered = strings.Select("NOT Value LIKE '*water*' OR (Value LIKE '*ice*' AND Value LIKE '*fruit juice*')");
Also note that in this case, since the string fruit juice already contains the string ice, the second condition is redundant. You'd have to find a way to express "words" and not "substrings".
In the end, you might be better off implementing the parsing logic yourself.
I'm trying to implement method Find that searches the database.
I forgot to mention that I'm using Postgresql, so I can't use built in LINQ to SQL.
I want it to be like that:
var user = User.Find(a => a.LastName == "Brown");
Like it's done in List class. But when I go to List's source code (thanks, Reflector), I see this:
public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
How can I implement this thing? I need to get those parameters to make the search.
Solution
Okay, I understood now that I need to do LINQ to SQL to do all this good expressions stuff, otherwise I'd have to spend a lot of time reimplementeing the wheel.
Since I can't use LINQ to SQL, I implemented this easy method:
public static User Find(User match, string orderBy = "")
{
string query = "";
if (!String.IsNullOrEmpty(match.FirstName)) query += "first_name='" + match.FirstName + "'";
if (!String.IsNullOrEmpty(match.LastName)) query += "last_name='" + match.LastName+ "'";
return Find(query + (!String.IsNullOrEmpty(orderBy) ? orderBy : ""));
}
This is how to use it:
var user = User.Find(new User { FirstName = "Bob", LastName = "Brown" });
Your method should accept Expression<Func<User>>.
This will give you expression tree instead of delegate which you can analyze and serialize to SQL or convert to any other API call your database have.
If you want everything to be generic, you may wish to go on with implementing IQueryable interface. Useful information can be found here: LINQ Tips: Implementing IQueryable Provider
Although for a simple scenario I would suggest not to complicate everything and stick with using Expression Trees and returning plain IEnumerable<T> or even List<T>.
For your case first version of code could look like this:
public IEnumerable<T> Get(Expression<Func<T, bool>> condition)
{
if (condition.Body.NodeType == ExpressionType.Equal)
{
var equalityExpression = ((BinaryExpression)condition.Body);
var column = ((MemberExpression)equalityExpression.Left).Member.Name;
var value = ((ConstantExpression)equalityExpression.Right).Value;
var table = typeof(T).Name;
var sql = string.Format("select * from {0} where {1} = '{2}'", table, column, value);
return ExecuteSelect(sql);
}
return Enumerable.Empty<T>();
}
And it's complexity grows fast when you want to handle new and new scenarios so make sure you have reliable unit tests for each scenario.
C# Samples for Visual Studio 2008 contain ExpressionTreeVisualizer that will help you to dig into Expression Trees more easily to understand how to extract information you need from it.
And of course, if you can stick with using existing implementation of LINQ, I would suggest to do it. There are Linq to SQL for SQL Server databases, Linq to Entities for many different databases, Linq to NHibernate for NHbernate projects.
Many other LINQ providers can be found here: Link to Everything: A List of LINQ Providers. Amount of work to implement LINQ provider is not trivial so it's a good idea to reuse tested and supported solution.
Exactly the same way. Just replace this._items with your users collection.
Also replace the type parameter T with the type User.
A lambda expression in source code can be converted to either a compiled executable delegate or an expression tree upon compilation. Usually we associate lambda's with delegates but in your case since you say you want access to the parameters (in this case I assume you mean LastName and "Brown" then you want an expression tree.
Once you have an expression tree, you can parse it to see exactly what it is an translate it to whatever you actually need to do.
Here are a few questions about expression trees.
Expression trees for dummies?
Bit Curious to understand Expression Tree in .NET
Sounds like you're definitely reinventing a very complicated wheel though. I'm sure it'll be a useful learning experience, but you should look into LINQ to Entities or LINQ to SQL for real-world programming.
Maybe I just haven't understood the question, but there's already a method for doing what you want: Enumerable.Where.
If you need to find a single element then use SingleOrDefault or FirstOrDefault instead.
You could do it something like this:
public static IEnumerable<User> Find(Predicate<User> match)
{
//I'm not sure of the name
using (var cn = new NpgsqlConnection("..your connection string..") )
using (var cmd = new NpgsqlCommand("SELECT * FROM Users", cn))
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
var user = BuildUserObjectFromIDataRecord(rdr);
if (match(user)) yield return user;
}
}
}
And then you can call it like this
var users = User.Find(a => a.LastName == "Brown");
Note that this returns any number of users, you still have to implement the BuildUserObjectFromIDataRecord() function, and that it will always want to iterate over the entire users table. But it gives you the exact semantics you want.
Okay, I understood now that I need to do LINQ to SQL to do all this good expressions stuff, otherwise I'd have to spend a lot of time reimplementeing the wheel.
Since I can't use LINQ to SQL, I implemented this easy method:
public static User Find(User match, string orderBy = "")
{
string query = "";
if (!String.IsNullOrEmpty(match.FirstName)) query += "first_name='" + match.FirstName + "'";
if (!String.IsNullOrEmpty(match.LastName)) query += "last_name='" + match.LastName+ "'";
return Find(query + (!String.IsNullOrEmpty(orderBy) ? orderBy : ""));
}
This is how to use it:
var user = User.Find(new User { FirstName = "Bob", LastName = "Brown" });
One way would be to create an anonymous delegate, like so:
Predicate<User> Finder = delegate(User user)
{
return user.LastName == "Brown";
}
var User = User.Find(Finder);