Perform left join with Include() with Linq in C# - c#

I'm facing an issue with Entity Framework Core in C#. I have created a function to return the list of Organisation from my database. For each organisation, I have two tables:
OrganisationUser: the link with Organisation is the OrganisationId. This table is linked to the Licence table with the LicenceId
Invitation the link with Organisation is the OrganisationId. This table is linked to the Licence table with the LicenceId
If I run the query I received, as I expected, the list of organisations with all details.
public IQueryable<Organisation> GetOrganisationsByBillingDay(int billingDay)
{
return _context.Organisation
.Include(org => org.OrganisationUser)
.ThenInclude(usr => usr.License)
.Include(org => org.Invitation)
.ThenInclude(i => i.License)
.Where(o => o.BillingDay == billingDay);
}
In this list the organisation that doesn't have any records in OrganisationUser or Invitation are excluded.
How is it possible to include them? Is there a diffrent way than writing a query with Linq?
Update
If you look at the query Linq creates it ia a left join.
The configuration is
builder.Services.AddDbContext<BillingContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("BillingDatabase"),
providerOptions => providerOptions.EnableRetryOnFailure()
));
Last Update
As you can see in the screenshot, Linq performs left join queries. I have now what I'm looking for. The problem was in the data not in the code.

If it is optional, then your navigation property will either be null or an empty collection depending upon what the cardinality of relationship is. There is nothing special you need to do as the join is implied by Include() but not explicitly specified by the user in the query itself.
The most likely issue is your relationship definition. Can you share your model config?

Related

C# Entity Framework: Linq Filter on GrandChildren and Conduct a Select on the Parent with Attributes

Our company is currently using Entity Framework Net Core 2.2 with Sql Server
Trying to find all Distinct customers who purchased a certain Product Input Parameter .
The following EF Linq query was written to get the distinct Customers.
Later another question came up, how do we get more (navigation) properties of customer? Should Include be placed Before the Where or After the Where? Does it matter? When running the SQL Profiler, it noted no difference in the queries. I just wanted to be sure in some cases does the location of Include here matter?
select distinct c.customerName
from dbo.customer customer
inner join dbo.Transactions transaction
on transaction.customerid = customer.customerid
inner join dbo.Purchases purchases
on purchases.PurchaseId = transaction.PurchaseId
inner join dbo.Product product
on transaction.ProductId = product.ProductId
where tra.BKProduct = #ProductInput
Original Solution: C# Entity Framework: Linq Filter on GrandChildren and Conduct a Select on the Parent
var customerData = db.Customer
.Where(p => p.Transactions.SelectMany(c => c.Purchases).Select(gc => gc.Product.Where(gc => gc.BKProduct == ProductInput).Any());
Another question came up, we need to get more (navigation) properties of Customer.
Alternative 1:
var customerData = db.Customer
.Include(c=>c.CustomerType)
.Include(c=>c.CustomerAddress)
.Where(p => p.Transactions.SelectMany(c => c.Purchases).Select(gc => gc.Product.Where(gc => gc.BKProduct == ProductInput).Any());
Alternative 2:
var customerData = db.Customer
.Where(p => p.Transactions.SelectMany(c => c.Purchases).Select(gc => gc.Product.Where(gc => gc.BKProduct == ProductInput).Any())
.Include(c=>c.CustomerType)
.Include(c=>c.CustomerAddress)
In this specific case, it probably does not matter.
Since c# "Include" is about the SELECT and the JOIN of the generated sql.
However, you do not want to use the "it does not matter" as a blanket statement.
See here answer below (and overall question and other answers).
Does the order of LINQ functions matter?
When you start putting in things like Where and OrderBy, the order-of-the-operations can matter.
Always look at the generated sql and ask yourself "does it look reasonable"? (Which you already did from your question :) ..I mention primarily this for future readers)
So in this specific case, it is a preference. I typically put .Where
last. So your first example would match my personal preference.
And for some "further investigation", check out something like : https://weblogs.asp.net/dixin/introducing-linq-3-waht-is-functional-programming

Entity Framework 7 filtering a child collection

I will try and specify this as simply as I can, I am using EF7.
I have two tables - Report, and ReportCategories, these are linked via a reportCategoryMap table which has a foreign key constraint to both tables (EF data model of both tables has hashset of reportcategorymap)
I want to filter upon report info but additionally want to filter the report categories that come back. To simplify my query it is as follows
_dbContext.Reports.Where(r => r.reportId == 1)
.Select(r => new Report
{ReportId = r.ReportId,
ReportCategoryMap = r.ReportCategoryMap.Where(rc => !rc.IsDeleted)
}
The problem is that the ReportCategory objects in the returned ReportCategoryMap collections are always empty. I have tried putting in a
_dbContext.Reports.Include(r => r.ReportCategoryMap).ThenInclude(rcm => rcm.ReportCategory).Where ....
But this does not work.
If I remove the Select then the values come back but the CategoryMap is not filtered when Categories are not deleted. I can always put the filtering logic after the query is run but hopefully I'm doing something foolish and someone can help me in the linq query
Hope that makes sense.

How to restrict LINQ query to marketing lists of a given campaign?

I'm using LINQ to query the CRM, and below you can see what I already have. The goal is to restrict the query to marketing lists, that are attached to a given campaign. How can I do this in LINQ (with late binding)?
List<Guid> GetLists(OrganizationServiceContext context, Guid campaign)
{
var lists =
from list in context.CreateQuery("list")
where /* list is attached to campaign */
select (Guid)list["listid"];
return lists.ToList<Guid>();
}
Premise: I upvoted the question because it's very interesting (I like LINQ against late bound) and the entities involved are not so easy to be queried.
First the code:
var lists = from list in context.CreateQuery("list")
join campaignlist in context.CreateQuery("campaignitem") on list["listid"] equals campaignlist["entityid"]
join campaign in context.CreateQuery("campaign") on campaignlist["campaignid"] equals campaign["campaignid"]
where (Guid)campaign["campaignid"] == campaignId
select (Guid)list["listid"];
And now the explanation:
As you already know list and campaign are connected with an N:N relationship, first thing to do is to find the relationship name, inside CRM it's under the relationship properties, in this case is campaignitem.
The second thing to do is to find the foreign key names of the relationship, normally they are entitynameid (so we can expect listid and campaignid) but in this case not. Instead of listid we have entityid (this because this relationship holds not only the relationship between marketing list and campaign but also between campaign and products and others as well.

Getting only specific columns in entity framework lambda join

I am surprised I cannot find a solution for this on the web, but wording the search terms was a bit difficult. The question I have is about generating entity SQL that only returns the needed columns in a group join using Lambda syntax.
The following is a "toy" example. I am not joining on two entities, rather on an enumerated list and an entity. And tunnelling is not an acceptable answer. I need to apply this to a much larger problem using a group join and select many.
var result1 = clientprofiles.Join(Context.Adjusters,
c => c.AdjusterId,
a => a.AdjusterId,
(c, a) => new {a.ClientAccountId}).ToList();
Using Julie Lehrman's Entity profiler, I see that the query is being generated to select every record in the rows that meet the join criteria. How do I pare it down so it only selects the ClientAccountId field in this example?
You can project a set of columns on any select from the context, so in your case you can constrain the Context.Adjusters parameter by using
Context.Adjusters.Select(a=> new { a.ClientAccountId })
to constrain the query to just the single column

Improve linq query speed using join

I'm not used with linq. I use EF 4.0. I'm always using lambda expression to get my data like this:
List<User> users = db.Users
.Include(u => u.Licences)
.Include(u => u.Licences.Select(l => l.LicenceProducts.Select(lp => lp.Product)))
.Include(u => u.UserAddress)
.Include(u => u.Contact)
.Include(u => u.User2)
.Include(u => u.SupportProducts)
.Where(u => u.Type != (int)UserType.Admin)
.OrderBy(u => u.Name)
.ToList();
Unfortunately, it takes a lot of time to execute. So, I want to change it by using left joins but I'm not understanding correctly the way joins are working in Linq.
Here's what I tried:
users = from user in db.Users
join licence in db.Licences on user.UserID equals licence.UserID
join licenceProduct in db.LicenceProducts on licence.LicenceID equals licenceProduct.LicenceID...;
The type that it returns, is not the same as it was previously (List)
I also tried this but I have the same problem
users = db.Users
.Join(db.Licences, lic => lic.UserID, user => user.UserID, (user, lic) => new { user, lic })
Joins don't do the same as Include. Includes tell EF to populate associated navigation properties off the entity that's in the main query. Joins, however, only execute a SQL joins, but don't populate anything.
You typically use joins if you want to filter on properties in child or parent objects. Like join c in Contacts ... where c.Name == "..." – this only returns Users without any contacts populated. The SQL SELECT clause only contains User columns. (Well, assuming you only select distinct users).
Includes also produce SQL joins, but at the same time put all columns of the included entities in the SELECT clause. The query result set is used to materialize all included entities. When there are many Includes, this result will blow up incredibly in width and length. In width, because it selects all columns of all included entities. In length because each included child collection multiplies the result set by its number of rows.
Therefore it is recommended to have no more than three Includes. So I think you have to reconsider the number of Includes you really need. It's probably much more efficient to load associated entities in separate queries.
The joins you are using are inner joins, not left joins. You can use DefaultIfEmpty() to turn them into left joins, as described here: http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx
Also, note that using linq you are creating a query, not a list. The query only gets executed when the results need to be retrieved. You can call ToList() to do this. In general, if you are using LINQ for retrieving data it is important to read about deferred execution (good explanation here: http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx), otherwise the data you get may not be what you are expecting if it changes between the time the query is created and the time that it gets executed.
Also, for that many includes I think that using a stored procedure be easier.

Categories