Inner join in Entity Framework - c#

I have been having a problem with the following query I constructed it keeps returning null, I am hoping that someone could just point me in the right direction.
The query is meant to return a list of branches that offer a particular service based on a service ID that is given. I have a many-to-many relationship between two tables being branches and services.
from b in database.branches
join bs in database.branch_services on b.branch_id equals bs.branch_id
where bs.service_id == objID
select b;

Here is the valid query, adjust table names to match yours:
database.Services.Where(s => s.ServiceId == 3).First().Branches.ToList();

Have you tried the lambda syntax?

Related

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)

DefaultIfEmpty() Causing "System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable'"

Scenario: I have a table of User Profiles and a table of Colleagues. The colleagues table has a record for ever other user that a User Profile is following. In this query, I am grabbing all of the people who are following the current logged in user (getting their Record IDs from the Colleagues table and joining the User Profile table to get their details). Then, I am joining the Colleagues table again to see if the logged in user is following that user back.
Issue: It is my understanding that the best way to do a LEFT JOIN (in looking for the colleague record where the user is following the colleague back) is to add "DefaultIfEmpty()" to that join. When I add .DefaultIFEmpty() to that join, I get the following error message:
System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable'
If I remove the ".DefaultIFEmpty()" from that join, it works. However, it runs it as a regular JOIN, leaving out records where the user is not following the colleague back.
Code: Here is the code I am using:
var results = (from a1 in db.Colleague
join b1 in db.UserProfile on new {ColleagueId = a1.ColleagueId} equals
new {ColleagueId = b1.RecordId}
join d1 in db.UserProfile on new {RecordId = a1.OwnerId} equals
new {RecordId = d1.RecordId}
join c1 in db.Colleague
on new {OwnerId = b1.RecordId, Ignored = false, ColleagueId = a1.OwnerId}
equals new {c1.OwnerId, c1.Ignored, c1.ColleagueId} into c1Join
from c1 in c1Join.DefaultIfEmpty() // This is the .DefaultIfEmpty() breaking the query
where
b1.AccountName == userName &&
a1.Ignored == false
orderby
b1.LastName
select new
{
RecordId = (System.Int64?) d1.RecordId,
d1.AccountName,
d1.PreferredName,
d1.FirstName,
d1.LastName,
d1.PictureUrl,
d1.PublicUrl,
IsFollowing = c1.OwnerId < 1 ? 0 : 1
});
foreach (var result in results) // This is what throws the error
{
// Do stuff
}
Any ideas?
The SQL Provider for Entity Framework in version 3.5 of the .NET framework does not support DefaultIfEmpty(). Sorry, but could not find a better reference than this article: http://smehrozalam.wordpress.com/2009/06/10/c-left-outer-joins-with-linq/
You might want to try straight LINQ-to-SQL rather than ADO.NET Entity Framework. I believe that it works in LINQ-to-SQL. I've verified in the past that left joins work in 3.5 via LinqPad.
DefaultIfEmpty is supported only in EFv4+. First version of EF doesn't support DefaultInEmpty.
It looks like you need to create a default value to pass into DefaultIfEmpty(), since DefaultIsEmpty() takes a parameter.
DefaultIfEmpty() on MSDN

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.

Why doesn't nhibernate LINQ support simple outer joins (given a where clause on the outer joined table)?

i have tableA and tableB
tableA has a B_Id property.
This query works fine:
IEnumerable<A> a = Session.Query<A>().Fetch(r=>r.B);
but i want something like:
IEnumerable<A> a = Session.Query<A>().Where(r=>r.B.Active).Fetch(r=>r.B);
it seems like when i do this, it no longer does a simple outer join and if there are no active records in table B, i get no results.
I want to do a pure outerjoin that will still give me results but with the B property of the A entity as null.
Does nhibernate LINQ support this ability to put a where clause on your outerjoined table??
According to this post on the nhusers group it's apparently not supported, and you'll have to use HQL.
As to the why, I would speculate that the authors plan to add it but had higher priorities. Personally I'd see it as a key feature.
Guess: .Where(a => a.B == null || a.B.Active)
A thought: You're trying to select instances of A which will be in an unknown state. How should NHibernate differ between instances of A where B == null and B.Active == false?
Both will, if it worked, return null values for B and A would be populated with a null reference. What should happen if you save A again? Should the reference to B be set to null? That would remove references when B.Active == false. Should it be untouched? That would make NHibernate store a state which doesn't represent your domain object.

Categories

Resources