In my application, I have Property Setting which is of type String.Collections.Specialized.StringCollection. It contains a list of customer codes such as MSFT, SOF, IBM etc. I'm trying to use this in a Linq-to-Entities query in the where clause:
var ShippedOrders = dbcontext.Orders
.Where(s=>(s.Status.Description.Equals("Shipped") && !Properties.Settings.Default.CustomersToExclude.Contains(s.CustomerCode)));
This fails as Contains is not recognized by Linq-to-Entities with a message similar to:
"LINQ-to-Entities does not recognize the method Contains...."
How do I revise the code above to avoid this error?
A shorter path is
myProperties.Settings.Default.CustomersToExclude.Cast<string>().Contains(blah);
That's a handy trick for any situation where a collection isn't inherently LINQ-aware.
Since your question is tagged as C# 4 use a List<string> instead (StringCollection is ancient) and your query should work. Also you should resolve your list reference outside your query:
List<string> customersToExclude = ..
var ShippedOrders = dbcontext.Orders
.Where(s=>(s.Status.Description.Equals("Shipped")
&& !customersToExclude.Contains(s.CustomerCode)));
Edit:
Just copy your customers to an array and use that:
var customerstoExclude = new string[Properties.Settings.Default.CustomersToExclude.Count];
myProperties.Settings.Default.CustomersToExclude.CopyTo(customerstoExclude, 0);
This is answered in a related question. EF4 apparently supports Contains directly, though, so that'd be my prefered solution... :)
Related
I have executed a linq query by using Entityframework like below
GroupMaster getGroup = null;
getGroup = DataContext.Groups.FirstOrDefault(item => keyword.IndexOf(item.Keywords,StringComparison.OrdinalIgnoreCase)>=0 && item.IsEnabled)
when executing this method I got exception like below
LINQ to Entities does not recognize the method 'Int32 IndexOf(System.String, System.StringComparison)' method, and this
method cannot be translated into a store expression.
Contains() method by default case sensitive so again I need to convert to lower.Is there any method for checking a string match other than the contains method and is there any method to solve the indexOf method issue?
The IndexOf method Of string class will not recognized by Entity Framework, Please replace this function with SQLfunction or Canonical functions
You can also take help from here or maybe here
You can use below code sample:
DataContext.Groups.FirstOrDefault(item =>
System.Data.Objects.SqlClient.SqlFunctions.CharIndex(item.Keywords, keyword).Value >=0 && item.IsEnabled)
You really only have four options here.
Change the collation of the database globally. This can be done in several ways, a simple google search should reveal them.
Change the collation of individual tables or columns.
Use a stored procedure and specify the COLATE statement on your query
perform a query and return a large set of results, then filter in memory using Linq to Objects.
number 4 is not a good option unless your result set is pretty small. #3 is good if you can't change the database (but you can't use Linq with it).
numbers 1 and 2 are choices you need to make about your data model as a whole, or if you only want to do it on specific fields.
Changing the Servers collation:
http://technet.microsoft.com/en-us/library/ms179254.aspx
Changing the Database Collation:
http://technet.microsoft.com/en-us/library/ms179254.aspx
Changing the Columns Collation:
http://technet.microsoft.com/en-us/library/ms190920(v=sql.105).aspx
Using the Collate statement in a stored proc:
http://technet.microsoft.com/en-us/library/ms184391.aspx
Instead you can use this method below for lowering the cases:
var lowerCaseItem = item.ToLower();
If your item is of type string. Then this might get you through that exception.
Erik Funkenbush' answer is perfectly valid when looking at it like a database problem. But I get the feeling that you need a better structure for keeping data regarding keywords if you want to traverse them efficiently.
Note that this answer isn't intended to be better, it is intended to fix the problem in your data model rather than making the environment adapt to the current (apparently flawed, since there is an issue) data model you have.
My main suggestion, regardless of time constraint (I realize this isn't the easiest fix) would be to add a separate table for the keywords (with a many-to-many relationship with its related classes).
[GROUPS] * ------- * [KEYWORD]
This should allow for you to search for the keyword, and only then retrieve the items that have that keyword related to it (based on ID rather than a compound string).
int? keywordID = DataContext.Keywords.Where(x => x.Name == keywordFilter).Select(x => x.Id).FirstOrDefault();
if(keywordID != null)
{
getGroup = DataContext.Groups.FirstOrDefault(group => group.Keywords.Any(kw => kw.Id == keywordID));
}
But I can understand completely if this type of fix is not possible anymore in the current project. I wanted to mention it though, in case anyone in the future stumbles on this question and still has the option for improving the data structure.
I have the need to update a subdocument in Mongo, and this is how I did it. This screenshot shows what my documents look like. And the code below it shows how I updated Geddy’s name and instrument.
Note: This approach was taken from this SO post:
var update = Update.Set("Members.$.Instrument", "Keyboards").Set("Members.$.LastName", "Leex");
var collection = MongoDbHelper.Db.GetCollection<Band>("Bands");
collection.Update(Query.And(Query.EQ("Name", "Rush"), Query.EQ("Members.FirstName", "Geddy")), update);
Is there another/better way to do this that makes use of strongly-typed properties instead of all of these string literals?
There is currently no support for writing queries or updates like this one (i.e. querying against individual subfields of arrays and using "$" in the update) using the typed builders.
The difficulty is coming up with expressions that compile without errors and yet express the desired intent correctly.
For example, the following might be a workable design, but using -1 as an index value is kind of hacky:
var query = Query.And(
Query<Band>.EQ(b => b.Name == "Rush"),
Query<Band>.EQ(b => b.Members[-1].FirstName == "Geddy"));
var update = Update<Band>
.Set(b => b.Members[-1].Instrument, "Keyboards")
.Set(b => b.Members[-1].LastName, "Leex");
Note: this is just a possible design for supporting "$" in typed builders. It is not actually implemented this way.
If you have any ideas for how a type safe version of this could be expressed you should create a JIRA ticket suggesting the feature.
I have dynamic linq WHERE statement:
dataContext.Table.Where("id = 0 Or id = 1 Or id = 2 Or ...");
I want change to:
dataContext.Table.Where("id IN (0, 1, 2, ...)");
But it doesn´t work. How can I do this for better performance?
From How to use “contains” or “like” in a dynamic linq query?
//edit: this is probably broken, see below
ids = new int[] {1,2,3,4};
dataContext.Table.Where("id.Contains(#0)", ids);
Aside: It is good practice to use placeholders in dynamic linq expressions. Otherwise you may open yourself to linq injection attacks (Is Injection Possible through Dynamic LINQ?)
EDIT:
actually I think I messed this up.
Unfortunately I cannot test this at the moment.
But I think the correct syntax in this case should be dataContext.Table.Where("#0.Contains(id)",ids);, not the other way around, and that version does not work out-of-the-box.
See here for a way to add this functionality to dynamic link. You need to modify the library for this.
var ids = new int[] {1,2,3,4};
dataContext.Table.Where(f => ids.Contains(f.id))
it seems that in version 1.0.4 of System.Linq.Dynamic , we can use the following syntax dataContext.Table.Where("#0.Contains(outerIt.id)",ids); as it was made and presented in the already cited blog:
here
I am new at LINQ and really need a help with some coding.
At the moment, I have a string and a var variables.
string temp = "from product in myEntities.Products where product.Name.Contains(_Name) select product";
var _Products = temp;
LvProducts.DataSource = _Products;
LvProducts.DataBind();
Basically, what I want to do is to be able to create a custom/complicated LINQ query by assigning it into a string beforehand. After done with composing, I assign the string into the var variable. However, this is obviously will not work. Therefore, can anyone assist me on this?
You have a few options:
Use the the Dynamic Linq
libraries to construct you queries on
the fly. The best place to get
started is by reading ScottGu's blog
entry. However, I don't think
these libraries support the contains
method in your example. Here is
a blog post explaining how to add
this support.
Directly execute SQL statements. Check out the MSDN docs for Linq to Sql or Linq to Entities.
var _Products = myEntities.ExecuteStoreQuery<Product>
(#"SELECT * FROM Products WHERE [Name] In ('Item1', 'Item2')");
Use Linq's composable behaviour. This might not be the most elegant solution but it works really well if you do not have too many options. You can just construct your query in multiple parts.
var _Products = from product in myEntities.Products
select product
_Products = from product in _Products
where product.Name.Contains(_Name)
select product
if FilterByPrice {
_Products = from product in _Products
where product.Price > 100
select product
}
You can do this by compiling this Linq within some c# using the CodeDomProvider - Adding scripting functionality to .NET applications - but this is quite heavyweight as a solution. If you want to see more about how to do this, then take a look at LinqPad - http://www.linqpad.net - the author invites you to use the decompiler to see how it works!
If the requirement is just down to simple where clauses than an alternative might be to use Dynamic Linq - see Scott Gu's posts and the sample code from Microsoft - http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Maybe this can help you
http://nlinq.codeplex.com/
BR.
Much of the reason you use LINQ in the first place is to get compiler-verified queries, that wil ldetect errors at compile time. This will defeat that purpose since the string will be parsed at runtime.
For your needs you have two options:
1) Making a eSQL query and running it on the ObjectContext. Using this, you can still use your entities like myEntities.Products, and return a list of products.
2) Using a normal SQL query, and use the ObjectContext to call that directly towards the underlying database.
My guess is that you will have to use dynamic code execution. For further details, have a look at Ricks post on west-wind.
you're thinking of it like a Dynamic SQL where you create the statement as string and parse it as a SQL statement.
Since you're already in the code, why not make the statements right in there. It would be a lot easier if you use Lambda instead of the traditional linq. my 2 cents.
If I have a structure like this
Albums
- Album
- Discs
- Tracks
and I want to order a collection of albums by the title of the first track on the first disc.
Is there something similar to the following I could do (keeping in mind I need to use the OrderBy extension method that accepts a string)?
albums.OrderBy("Discs[0].Tracks[0].Title")
I need to be able to sort using a string expression thus the need to use the OrderBy method i.e. albums.OrderBy("Track[0].Title"). The reason for this is our custom framework uses a sort expression (e.g. "Title") passed back from a GridView which is looked up in a dictionary (e.g. "Track[0].Title") to get the correct order by clause. That is, the field and direction of sorting is dynamically determined at runtime.
or
albums.OrderBy("Discs.First().Tracks.First().Title")
Untested, but how about:
var query = from album in albums
let disc = album.Discs.First()
let track = disc.Tracks.First()
orderby track.Title
select album;
LINQ has two ways to query "from . in .." and Lambda expressions. They way you were almost writing it looked Lambda-ish. Here would be the Lambda expression:
albums.OrderBy(a=>a.Discs.First().Tracks.First().Title)
I used variable 'a' to indicate album but you can use any variable, this is identical to the first expression:
albums.OrderBy(album=>album.Discs.First().Tracks.First().Title)
or you can use the from obj in obj form as mention in the other answers.
How about this, in order to satisfy your need for an initial query that does not perform the sorting? This uses anonymous types to store the album information, plus the name of the first track so you can sort on it later.
var query = from album in albums
let disc = album.Discs.First()
let track = disc.Tracks.First()
select new { Album = album, FirstTrack = track.Title };
var sortedQuery = from album in query
order by album.FirstTrack
select album.Album;
Sorry people,
It looks like the OrderBy method that I am asking about and trying to use is specific to the ORM (genom-e) that we are using and is not reflected on the .net Queryable or IEnumerable classes (unlike the majority of genom-e's LINQ functionality). There is no OrderBy overload that accepts a string in .net, this is specific to genom-e.
Those of you using .net encountering a similar problem should probably give either of the above two answers a try.