I have this:
var sortName = Request.Params["sortName"];
var query = Request.Params["query"];
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).Contains(query));
The "uen.GetPropValue<string>(sortName)" will be filled dynamically with the sortName the user typed in the page.
For example, if an user looks for a person named "Joe", the snippet will be:
(uen => uen.namePerson.Contains(Joe))
But, I'm having problems with LINQ Case-sensitive searches. If I type "Joe", I will something. On the other hand, If I type "joe", it bring nothing.
How can I make this "Contains(sortName)" works with Case-Insensitive?? I've tried some things with String.Comparer but it reports errors on build solution.
Thanks!!
I believe the following will generate proper SQL:
uen=>(uen.GetPropValue<string>(sortName)).ToLower().Contains(query.ToLower()))
If this is really LINQ-to-SQL, try using the SqlMethods.Like method instead of String.Contains.
However, I think the problem is that this is NOT LINQ-to-SQL, because you are using delegates instead of Expression trees. So this is being brought client side, then executed locally ("LINQ to Objects"). Hence, String.Contains is doing what it does locally.
In that way, James's answer is correct, since he's calling ToLower() on both the value and the query. (Although, beware of culture issues -- perhaps specify which culture you want.)
You could also use the String.IndexOf Method (String, Int32, StringComparison) (http://msdn.microsoft.com/en-us/library/ms224424.aspx). This method allows you to specify if the matching should be done case-sensitively or not, and if it should use a Invariant culture or not.
So in your example:
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).IndexOf(query, 0, StringComparison.OrdinalIgnoreCase));
I'm not commenting on if this is a better solution than the one provided by James Curran. It could or could not be, performance wise.
This is the entire code:
var sortOrder = Request.Params["sortorder"];
var sortName = Request.Params["sortname"];
var query = Request.Params["query"];
IEnumerable<UsuarioEndereco> pagedEndereco;
Func<UsuarioEndereco, bool> whereClause = (uen => uen.GetPropValue<string>(sortName).Contains(query));
pagedEndereco = sortOrder.Equals("asc", StringComparison.CurrentCultureIgnoreCase) ?
_agendaServico.SelecionaUsuarioEnderecos(u.codUsuario).Where(whereClause).OrderByDescending(uen => uen.GetPropValue<IComparable>(sortName)) :
_agendaServico.SelecionaUsuarioEnderecos(u.codUsuario).Where(whereClause).OrderBy(uen => uen.GetPropValue<IComparable>(sortName));
The Extension Method GetPropValue is:
public static T GetPropValue<T>(this object component, string propertyName)
{
return (T)TypeDescriptor.GetProperties(component)[propertyName].GetValue(component);
}
Related
I am trying to use system.dynamic.linq to create dynamic sorting.
this, is the query that I use:
var query = dalSession.Query<T>().AsQueryable();
var res = (from x in query orderby "x.FirstName" select x)
this is the mysql output:
select
affiliate0_.id as id0_,
affiliate0_.first_name as first6_0_,
from affiliate affiliate0_ order by 'x.FirstName' //FirstName as well
So you can see that the output went to the mysql query is the direct string, and not its reflection, ('x.FirstName') or ('FirstName').
This has no meaning in mysql context, it looks like I need order by affiliate0_.first_name.
Is there anyway to provide the Nhibernate the member itself? So the compiled query will be done normally?
You have to remove the " from you requiry. "x.FirstName" is seen as a string and translated to a sql string.
The "x" has no meaning inside the dynamic string.
Remove the x. (i.e. leave just "FirstName") and it should work.
Using a method call instead of the query comprehension syntax, you'd get:
var res = query.Orderby("FirstName")
Did you try it as follows (as Diego suggested)?
(from x in query select x).OrderBy("FirstName")
Because I think the dynamic linq orderby extension method is not executed when you use (x => "FirstName")
Otherwise try this:
(from x in query select x).OrderBy("it.FirstName")
BTW I renamed the OrderBy method in Dynamic.cs to DynamicOrderBy because I had some situations where the not dynamic linq OrderBy method was executed too:
public static IQueryable<T> DynamicOrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) and use that one instead:
(from x in query select x).DynamicOrderBy("FirstName")
var param = Expression.Parameter("x");
var prop = Expression.Property(param, "FirstName");
var lambda = Expression.Lambda<Func<User, string>>(prop, param);
query.Orderby(lambda);
I have Ienumerable<string> collection that I want to concatenate into a single string with delimitor ;
for instance {"One","Two","Three"} -> "One;Two;Three;"
is it possible to do using the following function?
List<string> list = new List<string>(){"One","Two","Three"};
list.Aggregate<String>((x,y) => x + String.Format("{0};",y));
I have tried also this code:
list.Aggregate<String>((x,y) => String.Format("{0};{1}",x,y));
both samples didn't work.
EDIT: I see that it is not possible to do what I wanted using Linq-2-sql or Aggregate function in Linq-2-sql.
http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/dac496c0-5b37-43ba-a499-bb8eff178706/
EDIT2: the workaround I used is to go over the items returned by the original linq query...and copies them to a new list and do the join as suggested in the answers below on a linq object and not linq-2-sql object.
You can just use String.Join for this. If you're using .NET4 then you can use the overload that takes an IEnumerable<string> directly:
string joined = string.Join(";", list);
If you're using an older version of the framework then you'll need to use the overload that takes a string[] array instead, converting your collection to an array first if necessary:
string joined = string.Join(";", list.ToArray());
EDIT...
Of course, if you really want to use Aggregate for some reason then there's nothing stopping you. If so, it's usually recommended to build your string using a StringBuilder rather than multiple string allocations:
string joined = list.Aggregate(new StringBuilder(),
(sb, s) => sb.Append(s).Append(';'),
sb => (sb.Length > 0) ? sb.ToString(0, sb.Length - 1)
: "");
You can do it using below code
list.Aggregate((i, j) => i + ";" + j);
You'll need to provide an initializer, otherwise the first element will not have a ; added to it:
list.Aggregate<String>("", (x,y) => x + String.Format("{0};",y));
I am finding some unexpected behavior when using a projection in a LINQ to SQL query using a Func. Example code will explain better than words.
A basic L2S lambda query using projection:
db.Entities.Select(e => new DTO(e.Value));
It translates to the desired SQL:
SELECT [t1].[Value]
FROM [Entity] AS [t1]
However, when the projection is put into a Func like this:
Func<Entity, DTO> ToDTO = (e) => new DTO(e.Value);
And called like this:
db.Entities.Select(e => ToDTO(e));
The SQL is now pulling back all of the columns in the table, not just the one in the projection:
SELECT [t1].[Id], [t1].[Value], [t1].[timestamp], [t1].[etc...]
FROM [Entity] AS [t1]
So my question is, how do I encapsulate this projection without the LINQ to SQL instantiating the whole Entity?
Things to keep in mind, the DTO I am using has a protected default constructor, so I can't use an object initializer. And since the DTO class cannot be modified, I'd have to make a subclass to implement that behavior. Which is fine, if that's the only solution.
Thanks.
Edit:
Thanks to Brian for the solution. I had previously tried an Expression but couldn't figure out the syntax. Here's the working code:
Expression<Entity, DTO> ToDTO = (e) => new DTO(e.Value);
Then call it like this:
db.Entities.Select(ToDTO);
At first I was trying to call it like this, which wouldn't compile. This is the proper syntax for calling a Func, but not an Expression.
db.Entities.Select(e => ToDTO(e));
You probably need to create an Expression, not a Func
Expression<Func<Entity, DTO>> ToDTO = (e) => new DTO(e.Value);
IQueryable extension methods work with Expressions, not Funcs
By passing in a Func, you are probably invoking the IEnumerable extension method, which is why Linq2Sql is acting the way it is.
public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select new Story
{
Title = s.Title,
UserName = s.aspnet_User.UserName
}
);
return stories;
}
I need to pass this as IQueryable so the pagination helper I found online can only pull the items I need. The problem is that at runtime when the helper tries to do source.Count(); the compiler isn't a happy camper because it's an 'explicit contruction of an entity type query'.
How would I alter this LINQ to SQL method so this does not happen?
Also, to help me grasp this, why does the previous code not work and this one does?
public IQueryable<Story> FindAllStories(){
var stories = (from s in db.Stories
orderby s.DateEntered descending
select s);
return stories;
}
Update
I'm beginning to think the way to accomplish this (verified it works) is to create a POCO called UserStory. The new class has 2 properties: one of type Story and the other string UserName. I can then return an IQueryable of UserStory without a problem.
That's great; however, I still don't get why that method would work and my other doesn't. The other is adding a property of string UserName to my partial class Story and passing that object between layers. What's the difference?
The following link is to a blog post tat describes an issue similar to yours. It seems like the solution was to return a type that inherets from Story instead of a Story type:
http://devlicio.us/blogs/derik_whittaker/archive/2008/04/25/linq2sql-explicit-construction-of-entity-exception.aspx
Hope this helps.
I need to translate the following Code to an Expression and I will explain why:
results = results.Where(answer => answer.Question.Wording.Contains(term));
results is IQueryable<ISurveyAnswer>
Question is ISurveyQuestion
Wording is String
The problem is, Question is not always the name of the LINQ to SQL property.
This will give me the PropertyInfo for the actual ISurveyQuestion property
private static PropertyInfo FindNaturalProperty<TMemberType>(Type search)
{
IDictionary<string,PropertyInfo> properties = new Dictionary<string,PropertyInfo>();
search.GetProperties().Each(prop =>
{
if (null != prop.PropertyType.GetInterface(typeof(TMemberType).Name))
properties.Add(prop.Name, prop);
});
if (properties.Count < 1) throw new ArgumentException(String.Format("{0} has no properties of type {1}", search.Name, typeof(TMemberType).Name));
if (properties.Count == 1) return properties.Values.First();
search.GetInterfaces().Each(inter =>
{
inter.GetProperties().Each(prop =>
{
if (null != prop.PropertyType.GetInterface(typeof(TMemberType).Name))
properties.Remove(prop.Name);
});
});
if (properties.Count < 1) throw new ArgumentException(String.Format("{0} has no properties of type {1} that are not members of an interface", search.Name, typeof(TMemberType).Name));
if (properties.Count > 1) throw new AmbiguousMatchException(String.Format("{0} has more than one property that are of type {1} and are not members of an interface", search.Name, typeof(TMemberType).Name));
return properties.Values.First();
}
Once I have the PropertyInfo how do I translate that to an Expression Tree?
EDIT:
What I basically need is:
results = results.Where(answer => answer.GetQuestionProperty().GetValue(answer).Wording.Contains(term));
But that doesn't work so I need to build the Expression Tree myself, for linq-to-sql.
Reading the question I think what you're after is Dynamic Linq - which is a helper library to let you build Linq queries dynamically (!) using strings as opposed to at design time. That means that if you can get your property name you should be able create your query on the fly.
ScottGu has an article here
What your trying to do is create a dynamic query and you want the action tables / properties your query against to be dynamic as well. I am not sure if this is easily possible based on how you want to use it.
Check out ScottGu's blog post:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
and
Check out Rick Strahl's blog post:
http://www.west-wind.com/Weblog/posts/143814.aspx
http://www.linqpad.net/
linqpad will convert it for you.