linq case insensitive (without toUpper or toLower) - c#

public Articles GetByName(string name, Categories category, Companies company)
{
var query = from article in session.Linq<Articles>()
where article.Name == name &&
article.Category == category &&
article.Company == company
select article;
return query.FirstOrDefault();
}
how can query be case insensitive. I can use toLower or toUpper but i want with OrdinalIgnoreCase. Is it possible?

Use String.Equals with the appropriate parameters to make it case insensitive
mySource.Where(s => String.Equals(s, "Foo", StringComparison.CurrentCultureIgnoreCase));

Instead of == use the .Equals(name, StringComparison.OrdinalIgnoreCase) method.
var query = from article in session.Linq<Articles>()
where article.Name.Equals(name, StringComparison.OrdinalIgnoreCase) &&
article.Category.Equals(category) &&
article.Company.Equals(company)
select article;
return query.FirstOrDefault();

If this is a LINQ to SQL query against a database with a case-insensitive collation, then it already is case-insensitive. Remember that LINQ to SQL isn't actually executing your == call; it's looking at it as an expression and converting it to an equality operator in SQL.
If it's LINQ to Objects, then you can use String.Equals as the other posters have pointed out.

var query = from article in session.Linq<Articles>()
where string.Equals(article.Name,name, StringComparison.OrdinalIgnoreCase) &&
string.Equals(article.Category,category, StringComparison.OrdinalIgnoreCase) &&
string.Equals(article.Company,company, StringComparison.OrdinalIgnoreCase)
select article;
return query.FirstOrDefault();
It will also handle when Name,Category,Company is null

Use
String.Equals(article.Name, name, StringComparison.OrdinalIgnoreCase)

If you are using C# 6.0 you can define a short extension method to be used when constructing LINQ statements:
public static bool EqualsInsensitive(this string str, string value) => string.Equals(str, value, StringComparison.CurrentCultureIgnoreCase);
Usage:
query.Where(item => item.StringProperty.EqualsInsensitive(someStringValue));
For C# less than 6.0 it will look like this:
public static bool EqualsInsensitive(this string str, string value)
{
return string.Equals(str, value, StringComparison.CurrentCultureIgnoreCase);
}

Change it to
public Articles GetByName(string name, Categories category, Companies company)
{
var query = from article in session.Linq<Articles>()
where string.Equals(article.Name, StringComparison.CurrentCultureIgnoreCase) == name &&
string.Equals(article.Category, StringComparison.CurrentCultureIgnoreCase == category &&
string.Equals(article.Company, StringComparison.CurrentCultureIgnoreCase == company
select article;
return query.FirstOrDefault();
}

Use string.Equals(name, article.Name, StringComparison.OrdinalIgnoreCase) when you are sure that your database supports it.
E.g. SQLite with a collate of NOCASE will ignore the option.
Oracle uses session settings NLS_COMP, NLS_SORT that will be taken.
Else use ToLower() or ToUpper() when you have no culture issues.

Related

How to use Contains() function if field value is null in linq

I am working on a project where I use Linq for fetching data. Now I have a scenario where I have to check field value contains given string for that I use Contains() function.
Everything works fine, But when any of the field is null then it creates a problem.
personData = personData.Where(x => x.FirstName.ToLower().Contains(q.ToLower()) || x.LastName.ToLower().Contains(q.ToLower())).Select(x => x).ToList();
Here when FirstName or LastName field have a null value it throw an error.
So, how can I overcome from this problem ?
Use following approach: x.FirstName?.Contains(substring) ?? false
Since C# 6 you can use null-conditional operators, that simplifies some queries greatly. You can read more about this topic here
Please try this
personData = personData.Where(x => (x.FirstName != null && x.FirstName.ToLower().Contains(q.ToLower())) || (x.LastName != null && x.LastName.ToLower().Contains(q.ToLower()))).Select(x => x).ToList();
You must check first if required values are null, Try using the null-coalescing operator...
personData = personData.Where(x => ((x.FirstName.ToLower() ?? "").Contains(q.ToLower())) || ((x.LastName.ToLower() ?? "").Contains(q.ToLower()))).Select(x => x).ToList();
What about using a simple string extension like the following:
public static string AsNotNull(this string value)
{
if (string.IsNullOrWhiteSpace(value))
return string.Empty;
return value;
}
And then use it like:
x.FirstName.AsNotNull()
I think you should prevent ability to add null FirstName or LastName at the beggining. This kind of row seems unuseful.

How to use special characters for filtering results using LINQ?

I have the following code:
public IEnumerable<T> Enumerate<T>(IEnumerable<T> source, string searchField, string searchString,
bool searchEmpty) where T : class
{
if (source == null) throw new ArgumentNullException("source");
if (searchField == null) throw new ArgumentNullException("searchField");
if (searchString == null) throw new ArgumentNullException("searchString");
return from item in source.AsParallel()
let property = item.GetType().GetProperties().Where(_ =>
{
var searchFieldAttribute =
_.GetCustomAttributes(typeof (SearchFieldAttribute), false).SingleOrDefault() as
SearchFieldAttribute;
return searchFieldAttribute != null && Attribute.IsDefined(_, typeof (SearchFieldAttribute)) &&
searchFieldAttribute.Name == searchField;
}).Single()
let value = property.GetValue(item, null)
let asString = value == null ? String.Empty : value.ToString()
where
searchEmpty && String.IsNullOrEmpty(asString) ||
!searchEmpty && asString.ToLower().Contains(searchString.ToLower())
select item;
}
As you can see, I need to pass searchString parameter to this method and use it for searching or filtering source collection by checking whether string representation of property value contains searchString.
What should I improve in this method to use special characters (such as *, %, etc), which commonly used in search queries and LIKE statements in SQL. Is there any best practices, extensions or other implementations of Contains() method? Any advices and suggestions will be greatly appreciated.
After some searching attempts I've found solution from VB.NET language.
There is Operators.LikeString method that allows us to do wildcard matching, so the where clause should be rewritten as follows:
where
searchEmpty && String.IsNullOrEmpty(asString) ||
!searchEmpty && Operators.LikeString(asString.ToLower(), searchString.ToLower(), CompareMethod.Text)
And users will have possibilities to use special characters in their queries. Thanks for your attention.
NB. Microsoft.VisualBasic and Microsoft.VisualBasic.CompilerServices should be referenced.

Linq return string array

/// <summary>
/// Returns list of popular searches
/// </summary>
public static string[] getPopularSearches(int SectionID, int MaxToFetch)
{
using (MainContext db = new MainContext())
{
return (from c in db.tblSearches where c.SectionID == SectionID && c.Featured select new[] { c.Term });
}
}
I looked at other questions but they seem to be slightly different, I get the error:
Cannot implicitly convert type 'System.Linq.IQueryable<string[]>' to 'string[]'
I know this is probably simple, could someone point out what's wrong here please?
Sure - you're trying to return from a method declared to return a string[], but you're returning a query - which isn't a string in itself. The simplest way of converting a query to an array is to call the ToArray extension method.
However, as you're already selecting a string array for every element in the query, that would actually return string[][]. I suspect you really want to select a single string per query element, and then convert the whole thing into an array, i.e. code like this:
public static string[] GetPopularSearches(int sectionID, int maxToFetch)
{
using (MainContext db = new MainContext())
{
var query = from c in db.tblSearches
where c.SectionID == sectionID && c.Featured
select c.Term;
return query.Take(maxToFetch)
.ToArray();
}
}
Note that:
I've renamed the method and parameters to match .NET naming conventions
I've added a call to Take in order to use the maxToFetch parameter
You are attempting to return an unmaterialized query. The query is only evaluated when it is enumerated. Luckily for you, the ToArray method take the pain out of enumerating and storing. Simply adding it to the end of your query should fix everything.
return (
from c in db.tblSearches
where c.SectionID == SectionID && c.Featured
select new[] { c.Term }
).ToArray();
EDIT
Looking in more detail, perhaps:
return (
from c in db.tblSearches
where c.SectionID == SectionID && c.Featured
select new[] { c.Term }
).SelectMany(x => x).ToArray();
to flatten the results of your query, or even (less redundantly):
return (
from c in db.tblSearches
where c.SectionID == SectionID && c.Featured
select c.Term
).ToArray();
Add .ToArray() at the end of the return statement.

c# dealing with all possible null and non null values

I have the following method:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.CountryFrom.CountryName.Equals(CountryFrom,
StringComparison.OrdinalIgnoreCase));
}
What is the best way to write the where clause that would filter all the possible combinations of input parameters in one statement:
BOTH CountryFrom and CountryLoc = null
Only CountryFrom null
Only CountryLoc null
BOTH CountryFrom and CountryLoc are not null.
Soon .. I would need to filter out profiles by Age, Gender, Profession .. you name it.
I am trying to find a way to write it efficiently in C#. I know how to do it in a clean manner in TSQL. I wish I knew the way. Thanks for all the responses so far.
A good old binary XNOR operation will do the trick here:
db.Profiles.Where(p => !(p.CountryFrom == null ^ p.CountryTo == null))
It's effectively equating two booleans, though to me it's more direct, less convoluted even, than writing ((p.CountryFrom == null) == (p.CountryTo == null))!
I would use this simple LINQ syntax...
BOTH CountryFrom and CountryLoc = null
var result = from db.Profiles select p
where (p.CountryFrom == null) && (p.CountryLoc == null)
select p
Only CountryFrom null
var result = from db.Profiles select p
where (p.CountryFrom == null) && (p.CountryLoc != null)
select p
Only CountryLoc null
var result = from db.Profiles select p
where (p.CountryFrom != null) && (p.CountryLoc == null)
select p
BOTH CountryFrom and CountryLoc are not null.
var result = from db.Profiles select p
where (p.CountryFrom != null) && (p.CountryLoc != null)
select p
Hope it helps ;-)
I wouldn't call this elegant:
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p =>
{
p.ContryFrom != null &&
p.CountryFrom.CountryName != null &&
p.CountryFrom.CountryName.Equals(CountryFrom, StringComparison.OrdinalIgnoreCase)
});
}
I may be missing something, but as written, your combination of operators will either let all values through or no values through depending on whether you use || or && to combine them together.
I'm in favor of not trying to cram too much logic into a linq expression. Why not contain your comparison logic in a separate function like this?
EDIT: I provided an example implementation of the MatchesCountry function.
class Example
{
public IQueryable<Profile> FindAllProfiles(string CountryFrom, string CountryLoc)
{
return db.Profiles.Where(p => p.MatchesCountry(CountryFrom, CountryLoc));
}
}
public static class ProfileExtensions
{
public static bool MatchesCountry(this Profile profile, string CountryFrom, string CountryLoc)
{
// NOTE: Your comparison logic goes here. Below is an example implementation
// if the CountryFrom parameter was specified and matches the profile's CountryName property
if(!string.IsNullOrEmpty(CountryFrom) && string.Equals(profile.CountryName, CountryFrom, StringComparison.OrdinalIgnoreCase))
return true; // then a match is found
// if the CountryLoc parameter was specified and matches the profile's CountryCode property
if (!string.IsNullOrEmpty(CountryLoc) && string.Equals(profile.CountryCode, CountryLoc, StringComparison.OrdinalIgnoreCase))
return true; // then a match is found
// otherwise, no match was found
return false;
}
}

How can I conditionally apply a Linq operator?

We're working on a Log Viewer. The use will have the option to filter by user, severity, etc. In the Sql days I'd add to the query string, but I want to do it with Linq. How can I conditionally add where-clauses?
if you want to only filter if certain criteria is passed, do something like this
var logs = from log in context.Logs
select log;
if (filterBySeverity)
logs = logs.Where(p => p.Severity == severity);
if (filterByUser)
logs = logs.Where(p => p.User == user);
Doing so this way will allow your Expression tree to be exactly what you want. That way the SQL created will be exactly what you need and nothing less.
If you need to filter base on a List / Array use the following:
public List<Data> GetData(List<string> Numbers, List<string> Letters)
{
if (Numbers == null)
Numbers = new List<string>();
if (Letters == null)
Letters = new List<string>();
var q = from d in database.table
where (Numbers.Count == 0 || Numbers.Contains(d.Number))
where (Letters.Count == 0 || Letters.Contains(d.Letter))
select new Data
{
Number = d.Number,
Letter = d.Letter,
};
return q.ToList();
}
I ended using an answer similar to Daren's, but with an IQueryable interface:
IQueryable<Log> matches = m_Locator.Logs;
// Users filter
if (usersFilter)
matches = matches.Where(l => l.UserName == comboBoxUsers.Text);
// Severity filter
if (severityFilter)
matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);
Logs = (from log in matches
orderby log.EventTime descending
select log).ToList();
That builds up the query before hitting the database. The command won't run until .ToList() at the end.
I solved this with an extension method to allow LINQ to be conditionally enabled in the middle of a fluent expression. This removes the need to break up the expression with if statements.
.If() extension method:
public static IQueryable<TSource> If<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<IQueryable<TSource>, IQueryable<TSource>> branch)
{
return condition ? branch(source) : source;
}
This allows you to do this:
return context.Logs
.If(filterBySeverity, q => q.Where(p => p.Severity == severity))
.If(filterByUser, q => q.Where(p => p.User == user))
.ToList();
Here's also an IEnumerable<T> version which will handle most other LINQ expressions:
public static IEnumerable<TSource> If<TSource>(
this IEnumerable<TSource> source,
bool condition,
Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
{
return condition ? branch(source) : source;
}
When it comes to conditional linq, I am very fond of the filters and pipes pattern.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
Basically you create an extension method for each filter case that takes in the IQueryable and a parameter.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
Doing this:
bool lastNameSearch = true/false; // depending if they want to search by last name,
having this in the where statement:
where (lastNameSearch && name.LastNameSearch == "smith")
means that when the final query is created, if lastNameSearch is false the query will completely omit any SQL for the last name search.
Another option would be to use something like the PredicateBuilder discussed here.
It allows you to write code like the following:
var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone");
var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
.And (Product.IsSelling());
var query = from p in Data.Products.Where (newKids.Or (classics))
select p;
Note that I've only got this to work with Linq 2 SQL. EntityFramework does not implement Expression.Invoke, which is required for this method to work. I have a question regarding this issue here.
It isn't the prettiest thing but you can use a lambda expression and pass your conditions optionally. In TSQL I do a lot of the following to make parameters optional:
WHERE Field = #FieldVar OR #FieldVar IS NULL
You could duplicate the same style with a the following lambda (an example of checking authentication):
MyDataContext db = new MyDataContext();
void RunQuery(string param1, string param2, int? param3){
Func checkUser = user =>
((param1.Length > 0)? user.Param1 == param1 : 1 == 1) &&
((param2.Length > 0)? user.Param2 == param2 : 1 == 1) &&
((param3 != null)? user.Param3 == param3 : 1 == 1);
User foundUser = db.Users.SingleOrDefault(checkUser);
}
I had a similar requirement recently and eventually found this in he MSDN.
CSharp Samples for Visual Studio 2008
The classes included in the DynamicQuery sample of the download allow you to create dynamic queries at runtime in the following format:
var query =
db.Customers.
Where("City = #0 and Orders.Count >= #1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Using this you can build a query string dynamically at runtime and pass it into the Where() method:
string dynamicQueryString = "City = \"London\" and Order.Count >= 10";
var q = from c in db.Customers.Where(queryString, null)
orderby c.CompanyName
select c;
You can create and use this extension method
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
return isToExecute ? source.Where(predicate) : source;
}
Just use C#'s && operator:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Edit: Ah, need to read more carefully. You wanted to know how to conditionally add additional clauses. In that case, I have no idea. :) What I'd probably do is just prepare several queries, and execute the right one, depending on what I ended up needing.
You could use an external method:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
This would work, but can't be broken down into expression trees, which means Linq to SQL would run the check code against every record.
Alternatively:
var results =
from rec in GetSomeRecs()
where
(!filterBySeverity || rec.Severity == severity) &&
(!filterByUser|| rec.User == user)
select rec;
That might work in expression trees, meaning Linq to SQL would be optimised.
Well, what I thought was you could put the filter conditions into a generic list of Predicates:
var list = new List<string> { "me", "you", "meyou", "mow" };
var predicates = new List<Predicate<string>>();
predicates.Add(i => i.Contains("me"));
predicates.Add(i => i.EndsWith("w"));
var results = new List<string>();
foreach (var p in predicates)
results.AddRange(from i in list where p.Invoke(i) select i);
That results in a list containing "me", "meyou", and "mow".
You could optimize that by doing the foreach with the predicates in a totally different function that ORs all the predicates.

Categories