LINQ Join Query Structure Resulting in CS0119 Error - c#

I'm trying to join two different class models in an MVC project together so I can order them ascending/descending. I've tried several permutations but can't seem to get the LINQ query to play nice. Any suggestions on what I'm doing wrong?
var lateContact = from c in JPLatestContact
join s in JPStudent on c.ApplicationUserId equals
s.ApplicationUserId
orderby c.JPLatestContactDate ascending
select s;
I'm a beginner when it comes to this, but if I'm understanding this correctly, the "c" and "s" are variables I make up myself. "JPLatestContact" and "JPStudent" are the two models/classes/tables I want to join, and both have "ApplicationUserId" that I can join them on, and I want to order all the results by the value "JPLatestContactDate" found in the JPLatestContact model, in ascending order.
With the query I've written above, I'm getting a CS0119 error "'JPLatestContact' is a type, which is not valid in the given context."
I'm not sure where I'm going wrong with my structure, or have I misused the JOIN structure in some way?

You cannot run a LINQ select on a type, only on a collection of that type - i.e. anything that implements IEnumerable<JPLatestContact> or IQueryable<JPLatestContact>, such as List<JPLatestContact>, dbContext.JPLatestContact, etc. Same goes for JPStudent - you need a collection or IQueryable<JPStudent> for it.
Assuming that you are querying EF, the query should look like this:
var lateContact = from c in dbContext.JPLatestContact
join s in dbContext.JPStudent on c.ApplicationUserId equals
s.ApplicationUserId
orderby c.JPLatestContactDate ascending
select s;
Make sure that all entity names and property names match the actual names as defined in your EF model.

Related

How is OrderBy Applied?

I have the following query:
var vendors = (from pp in this.ProductPricings
join pic in this.ProductItemCompanies
on pp.CompanyId equals pic.CompanyId into left
from pic in left.DefaultIfEmpty()
orderby pp.EffectiveDate descending
group pp by new { pp.Company, SortOrder = (pic != null) ? pic.SortOrder : short.MinValue } into v
select v).OrderBy(z => z.Key.SortOrder);
Does anyone know how the last OrderBy() is applied? Does that become part of the SQL query, or are all the results loaded in to memory and then passed to OrderBy()?
And if it's the second case, is there any way to make it all one query? I only need the first item and it would be very inefficent to return all the results.
Well it will try to apply the OrderBy to the original query since you are still using an IQueryable - meaning it hasn't been converted to an IEnumerable or hydrated to a collection using ToList or an equivalent.
Whether it can or not depends on the complexity of the resulting query. You'd have to try it to find out. My guess is it will turn the main query into a subquery and layer on a "SELECT * FROM (...) ORDER BY SortOrder" outer query.
Given your specific example the order by in this situation most, likely be appliead as part of the expression tree when it getting build, there for it will be applied to sql generated by the LINQ query, if you would convert it to Enumarable like ToList as mentioned in another answer then Order by would be applied as an extension to Enumerable.
Might use readable code, because as you write it is not understandable.
You will have a problem in the future with the linq statement. The problem is that if your statement does not return any value the value will be null and whenever you make cause a exception.
You must be careful.
I recommend you to do everything separately to understand the code friend.

Comparison operators not support for 'System.String[]' in a Linq query

I'm working on a Linq query to join data from two tables (using Linq to SQL), with the logic as follows:
Banners contains a field which has comma separated values in it. I want to split this column and have a list of IDs (for example 1,2,3,4)
References contains a list of these mappings with 1:1 mapping between the ID in banners and the ID in the reference table
Once the tables are merged I want to return the description from the reference table, which is the text representation of the ID.
I've been fiddling with this for a while and have hit a brick wall. Below is the code I am using (in LinqPad):
var results = (from b in Banners
where b.BannerCode == "1234"
from a in b.VesselBoatAreaY.Split (',').AsEnumerable()
join r in References on a equals r.ReferenceCode
where r.Context == "TestContext"
select r.Description).ToList();
I have confirmed that the first part of the query works, i.e. that banner code exists and returns 4 separate values. When I run the query as a whole however I get the following:
NotSupportedException
Comparison operators not supported for type 'System.String[]'.
I have also tried the following:
var results = (from b in Banners
where b.BannerCode == "1234"
from a in b.VesselBoatAreaY.Split (',').AsEnumerable()
from r in References
where r.Context == "TestContext" &&
a.Contains(r.ReferenceCode)
select r.Description).ToList();
When I run this I get the following:
ArgumentException
The argument 'value' was the wrong type. Expected 'System.String'. Actual 'System.String[]'.
Any help appreciated!
Thanks for everyones help. I've solved the problem and it was actually very easy. As the table I am reading from is quite small I can apply AsEnumerable to the Banners table and it works fine. I realise this means it will get processed in memory, so it's not good for bigger tables, but its fine for what I need.
For reference the code is now:
var results = (from b in Banners.AsEnumerable()
where b.BannerCode == "1234"
from a in b.VesselBoatAreaY.Split (',')
from r in References.AsEnumerable()
where r.Context == "TestContext" &&
a.Contains(r.ReferenceCode)
select r.Description).ToList();

Exception in a CRM LINQ query with joins. Attribute in second table doesn't exist

First of all I'm sorry because this is the second time that I write this question but before was bad explained and now is close.
I'm doing a linq query for a search page for a CRM data base, and wrtiting a normal query like below is not working, I'm getting the exception:
[System.ServiceModel.FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>] = {"'Contact' entity doesn't contain attribute with Name = 'title'."}
For a join query, that in the clause Where was something like r.Name == "Me" && j.LastName == "He" I had to did the query with two Where clauses, because I was getting the same exception as above, saying that table 'r' doesn't have 'LastName' attributte.
var cms = from i in aux_pr
join cal in Contact on i.aux_CallerRequestorID.Id equals cal.ContactId.Value
join sub in Subject on i.aux_ClassificationID.Id equals sub.SubjectId
where cal.FullName.Contains(searchTerm) ||
sub.Title.Contains(searchTerm)
In this case, how can I do this query. Thanks in advance!
I want to comment what have I learned and the solution that I have found to my problem hoping could help some one. There are some limitations in CRM LINQ, as explained here
The first that I found, having an entity reference like this:
CrmEntityReference Caller
{
Guid ID;
string name;
}
I can select Caller.name but I CAN'T have Caller.name in the where clause. Solution for this -> Join the table
The second limitation, is when we have joins in the query, we can have different tables in the where if they are an AND predicate, we have to write two clauses where like this:
where cal.FullName.Contains(searchTerm)
where sub.Title.Contains(searchTerm)
But the problem comes when instead of an AND we need use an OR predicate, the only solution we have is do two queries and after do an Union of these queries.
I have four queries for a call that could be done just with one, now in developing stage performance is good due to the amount of records, but we'll see in testing stage how this work.
try to create two different filters..
var cms = from i in aux_pr
join cal in Contact on i.aux_CallerRequestorID.Id equals cal.ContactId.Value
join sub in Subject on i.aux_ClassificationID.Id equals sub.SubjectId
where cal.FullName.Contains(searchTerm) ||
where sub.Title.Contains(searchTerm)

How can I make this SelectMany use a Join?

Given that I have three tables (Customer, Orders, and OrderLines) in a Linq To Sql model where
Customer -- One to Many -> Orders -- One to Many -> OrderLines
When I use
var customer = Customers.First();
var manyWay = from o in customer.CustomerOrders
from l in o.OrderLines
select l;
I see one query getting the customer, that makes sense. Then I see a query for the customer's orders and then a single query for each order getting the order lines, rather than joining the two. Total of n + 1 queries (not counting getting customer)
But if I use
var tableWay = from o in Orders
from l in OrderLines
where o.Customer == customer
&& l.Order == o
select l;
Then instead of seeing a single query for each order getting the order lines, I see a single query joining the two tables. Total of 1 query (not counting getting customer)
I would prefer to use the first Linq query as it seems more readable to me, but why isn't L2S joining the tables as I would expect in the first query? Using LINQPad I see that the second query is being compiled into a SelectMany, though I see no alteration to the first query, not sure if that's a indicator to some problem in my query.
I think the key here is
customer.CustomerOrders
Thats an EntitySet, not an IQueryable, so your first query doesn't translate directly into a SQL query. Instead, it is interpreted as many queries, one for each Order.
That's my guess, anyway.
How about this:
Customers.First().CustomerOrders.SelectMany(item => item.OrderLines)
I am not 100% sure. But my guess is because you are traversing down the relationship that is how the query is built up, compared to the second solution where you are actually joining two sets by a value.
So after Francisco's answer and experimenting with LINQPad I have come up with a decent workaround.
var lines = from c in Customers
where c == customer
from o in c.CustomerOrders
from l in o.OrderLines
select l;
This forces the EntitySet into an Expression which the provider then turns into the appropriate query. The first two lines are the key, by querying the IQueryable and then putting the EntitySet in the SelectMany it becomes an expression. This works for the other operators as well, Where, Select, etc.
Try this query:
IQueryable<OrderLine> query =
from c in myDataContext.customers.Take(1)
from o in c.CustomerOrders
from l in o.OrderLines
select l;
You can go to the CustomerOrders property definition and see how the property acts when it used with an actual instance. When the property is used in a query expression, the behavior is up to the query provider - the property code is usually not run in that case.
See also this answer, which demonstrates a method that behaves differently in a query expression, than if it is actually called.

Child Entities not loaded when query joins tables

I have a many-to-many relationship where Content has ContentTags which point to a Tag. I've put the relevant [Include] attributes on my entities to create the properties.
If I write enumerate ObjectContext.Contents.Include("ContentTags.Tag") then I get the ContentTags and Tags included as expected. When I use a join however the ContentTags are missing from my Content entity:
var contentsForTag =
from c in ObjectContext.Contents.Include("ContentTags.Tag")
join ct in ObjectContext.ContentTags on c.Id equals ct.ContentId
join t in ObjectContext.Tags on ct.TagId equals t.Id
where t.Name.ToLower().Contains(lowerTag)
select c;
Any ideas what's going on here?
I'm not sure why this is happening but I think it is because of a contradiction.
The join says that EF should load only the tags that containes lowerTag but the Include says that all tags should be loaded. I would guess EF can't resolve this and that is why none are included. You should be able to write your query without the join though
var contentsForTag =
from c in ObjectContext.Contents.Include("ContentTags.Tag")
where c.ContentTags.Any(ct => ct.Tag.Name.ToLower().Contains(lowerTag))
select c;
Try the following:
var anonType =
from c in ObjectContext.Contents
join ct in ObjectContext.ContentTags on c.Id equals ct.ContentId
join t in ObjectContext.Tags on ct.TagId equals t.Id
where t.Name.ToLower().Contains(lowerTag)
select new { Contents = c, ContentTags = ct, Tags = t }).AsEnumerable();
IList<Contents> contentsForTag = anonType.Select(c => c.Contents).ToList();
If you drop all relevant tables into an anonymous type EF will understand that you in fact need all of that info and will bring it back. The best part is that EF will also take care of the auto-fixup, meaning all relationships will be maintained. The last line of the sample simply extracts the desired objects from the anonymous type into a strongly typed list, however the rest of the graph is still alive and well.
Sounds like a "lazy-load" vs "eager-load" difference. The collection of Tags for a Content class is stored in a child table. Many ORMs including EF try to "lazy-load" collections and other many-to-one references, because it doesn't know if you'll need them and it would be a waste of bandwidth if you didn't. However, this means your tags aren't available in retrieved instances. To tell L2E that, yes, you really do need the tags, you specify that the child reference should be "eagerly" traversed when building the context.

Categories

Resources