c# entity framework - query and join multiple tables / entities - c#

Assuming I have the following tables (with similarly formed models, plus a few virtual props)
Tabel 1: "AgentCompany" (Simply links an agents ID to a company)
AgentCompanyId, AgentId, CompanyId
Table 2: "Company"
CompanyId, CountryId
Table 3: "Country"
CountryId, Name
The model for AgentCompany has a virtual property for "Company" and The model for "Company" also has a virtual "Country" property.
My query currently looks like
var res = (from ap in Repo.AgentCompany
join p in Repo.Company on ap.CompanyId equals p.CompanyId
join c in Repo.Country on ap.Country.Name equals c.Name
where ap.AgentId == AgentFilter
select new AgentCompany
{
Company = p
});
This works, and i get all my data except that the Company (p) has its country as Null.
Im trying to fiugre out how to get this syntax to work so that since I can query the country as c shown above, i want p.Country = c, so in my AgentCompany object result, the Company property is the actual company, and the Company's virtual Country property points to a COuntry object.
Anyone know how I might achieve this? I have tried a few question searches and tried a few suggestions related to an inner join, or an "Include" method but I haven't been able to achieve what I want here.
Thanks in advance!

Related

Having trouble constructing the correct Linq query syntax in c#.net for a join after join

I have troubles creating the correct query for a list of applications I have. I need to display them in a dashboard so consultants can handle the applications.
These applications can be uploaded by organisations or individuals.
Every consultant is 'owner' of a few organisations and individuals, in the dashboard they should only see the applications from individuals/organisations that they are also the 'owner' of.
The applications table:
Application
-----------
ID | requestIndividualID | requestOrganisationID | ...
depending on who made the application the requesters ID will be saved in the table. So requestIndividualID or requestOrganisationID, one of them will be null, the other not.
The Individuals table:
Individual
----------
ID | name | ownerID
Now comes the tricky part, the ownerID is not on the Organisation table, but on the OrganisationSegment table, something like this:
Organisation
------------
ID | name | city
OrganisationSegment
-------------------
organisationID | ownerID
The problem comes when I want to join the Organisation table with the OrganisationsSegment table, since it is possible that the organisationID is null.
Currently I have this code that is throwing errors:
var applications = from pa in _context.Applications
join individu in _context.Individu on pa.requestIndividualID equals individu.ID into IndividuResultList
from individu in IndividuResultList.DefaultIfEmpty()
join organisation in _context.Organisations on pa.requestOrganisationID equals organisation.ID into organisationsList
from organisation in organisationsList
join organisationSegment in _context.OrganisationSegment on organisation.ID equals organisationSegment.OrganisationId into organisationSegmentList
from organisationSegment in organisationSegmentList.DefaultIfEmpty()
select new {Data = new {PortalApplications = pa, individu, organisation, organisationSegment}};
After this code I use the result to make a list where I can apply the filter for the owner Id.
When I execute this code, it throws System.InvalidOperationException : Nullable object must have a value. error.
My current solution is making 2 results, one for all the application that have a requestIndividualID and one for all the applications with a requestOrganisationID.
Then I apply the filter (the specific ownerID) to these 2 separate results, and adding the results in a list, since the results came from the same table, thats really easy.
But imo this is a quicky and dirty way of handling it.
I want the correct and clean answer.
Can somebody please help me?
Also i have trouble finding any help on the internet for this, so if you found some info, please link it as well, or tell me how to improve my google skills for issues like this (correct naming of the issue).
I believe this is easier if you join the Orginisation and OrginisationSegment tables first, assuming every Orginisation has an ownerID in OrginisationSegment.
var OrganisationsWithOwner = from o in _context.Organisations
join os in _context.OrganisationSegment on o.ID equals os.OrganisationId
join i in _context.Individu on os.OwnerID equals i.ID
select new { o, i };
Now you can join with Individu and the new OrginisationWithOwner and return the one that has a match.
var applications = from pa in _context.Applications
join indOwner in _context.Individu on pa.requestIndividualID equals indOwner.ID into IndividuResultList
from indOwner in IndividuResultList.DefaultIfEmpty()
join o in OrganisationsWithOwner on pa.requestOrganisationID equals o.o.ID into organisationsList
from o in organisationsList.DefaultIfEmpty()
select new { PortalApplications = pa, owner = (indOwner != null ? indOwner : o.i), organisation = o.o };

Get Specific object after a join using LINQ

I am trying to retrieve a specific class related to a table in Entity Framework using linq for join and where conditions as follows:
var result = (from a in db.Persons
join b in db.Person_IDs on a.PersonId equals b.PersonId
where b.FaceId == faceId
select new
{
PersonId = a.PersonId,
Name = a.Name,
Address = a.Address,
Picture = a.Picture,
City = a.City,
Estate = a.Estate,
Phone = a.Phone,
CellPhone = a.CellPhone,
BlackList = a.BlackList
}
).FirstOrDefault();
I would like the "result" object being returned as a Person object. In the above case, I need to create a new Person object and add the fields that came from the result.
Is it possible? I tried some ways and using some samples and researches but none of all alternatives worked for me.
Thanks!
UPDATE 1
All right, after some readings, the best way I found to do this was creating a DTO class for my Person object and returning this DTO class in my funcion as follows:
PersonDTO result = (from a in db.Persons
join b in db.Person_IDs on a.PersonId equals b.PersonId
where b.FaceId == faceId
select new PersonDTO
{
PersonId = a.PersonId,
Name = a.Name,
Address = a.Address,
Picture = a.Picture,
City = a.City,
Estate = a.Estate,
Phone = a.Phone,
CellPhone = a.CellPhone,
BlackList = a.BlackList
}
).FirstOrDefault();
db.Dispose();
return result;
All right, it worked fine, but one thing bothers me: why create another class identical to the EF class? Why can't EF class be used this way?
I am working with one table, but a program with, for example, 20 tables will force me to have 20 entity classes and 20 entity DTO classes!
As a beginner, I think this way of work a bit disorganized or nonsensical, making the traditional way (using data readers, commands and connections). Even being more bureaucratic, it don't have de need of "duplicated" objects.
Can somebody please provide this answer?
UPDATE 2
As requested: as I don't wat an anonymous type returning in my function, I tried returning the entity class (Person), but when I do this I get the following error in my application execution:
"The entity or complex type 'Models.Person' cannot be constructed in a LINQ to Entities query."
So the solution for this was create a DTO class (or a viewmodel class, whatever).
If you have Person objects in your database, and you want Person objects, why are you going to the trouble of creating an anonymous type?
Why not just try
var result = (from a in db.Persons
join b in db.Person_IDs on a.PersonId equals b.PersonId
where b.FaceId == faceId
select a).FirstOrDefault();
You should be able to do
var result = (from a in db.Persons
join b in db.Person_IDs on a.PersonId equals b.PersonId
where b.FaceId == faceId
select new Person
{
PersonId = a.PersonId,
Name = a.Name,
Address = a.Address,
Picture = a.Picture,
City = a.City,
Estate = a.Estate,
Phone = a.Phone,
CellPhone = a.CellPhone,
BlackList = a.BlackList
}).FirstOrDefault();
This should work as long as the Person class is accessible, it's location is imported, and it has public getters/setters with properties matching the above.
If you're still having issues, try including your class definition for person and any errors you might be seeing.
EDIT: Based on the error you are seeing, I'm guessing you're trying to select only SOME of the properties on this entity. EF actually won't let you do that. You can either select the whole entity (by not specifying the properties and just selecting a) or you can create a custom DTO that you can map to like I do above.
EF doesn't like incomplete mapping because it makes the state confusing for future model modifications. See this answer here. So if you're wanting to avoid loading the whole entity, go the custom DTO route.
you code is correct !! go for this solution as it has minimum modification
just select person
person result = (from a in db.Persons
join b in db.Person_IDs on a.PersonId equals
b.PersonId
where b.FaceId == faceId
select new person
{
PersonId = a.PersonId,
Name = a.Name,
Address = a.Address,
Picture = a.Picture,
City = a.City,
Estate = a.Estate,
Phone = a.Phone,
CellPhone = a.CellPhone,
BlackList = a.BlackList
}
).FirstOrDefault();

Outerjoin with a table of foreign keys in EF Data-first approach

I have a table Users which contain user information. I have a table Products which contain product information. I have a table called UserProduct which acts as a junction table and whose fields are UserId and ProductId. I am using a Entity Framework database first approach.
I want to outerjoin using Linq to find the following data.
All Users in the Users table.
All Users who have bought a particular product in terms of a Boolean called isPurchased.
My thinking was to left outer join table User with UserProduct and get all users and whether they have a product something like this.
var result = from a in Users
join b in UserProduct(Not available through EF) on a.Id equals b.prodId into group1
from g1 in group1.DefaultIfEmpty()
select new
{
id = g1.Id,
isPurchased = g1.prodId != null
}.ToList();
However in EF mapping, the object UserProduct is not created and so I cannot use it directly in my Linq query? So how do I go about this? Is there a way I can use linq to join tables with the actual table name(UserProduct) instead of joining entities?
Assuming Users contains a property List<Products> products to represent the junction information, and a variable boughtProductId to represent the particular product:
var result = from u in Users
let isPurchased = u.products.Any(p => p.Id == boughtProductId)
select new {
id = isPurchased ? boughtProductId : null,
isPurchased
}.ToList();

C# LINQ multiple one to many includes with where condition

I can't find the correct query to get all the data I need.
I've got three sample tables:
Employee (Id, Name, Telephone)
EmployeeDepartment (Id, EmployeeId, DepartmentId)
DepartmentAddress (Id, DepartmentId, City,
Street, IsActive...)
Each of this tables has one-to-many relation with next one. An Employee can be assigned to many departments and one department can have many addresses assigned.
I'm trying to write an Entity Framework query which will return, for example, all employees which are assigned to department in City of New York. My problem is that I don't want just employees. I need it to also include all properties of EmployeeDepartment and DepartmentAddress in Employee class.
What I'm trying to do is something like:
var matchingEmployees = ctx.Employee
.Include("EmployeeDepartment")
.Include("EmployeeDepartment.DepartmentAddress")
.Where(p=> p.EmployeeDepartment
.Where(x=>x.DepartmentAddress.Where(y=>y.City == "New York)))
.ToList();
As a result I get all Departments and all EmployeeDepartments, when I need only ones matching Where condition. What query will return the data I need?
You don't need to use the where like that just get to the condition directly. I think its something like that, if you post your entities it would be a little more easier.
var matchingEmployees = ctx.Employee
.Include("EmployeeDepartment")
.Include("EmployeeDepartment.DepartmentAddress")
.Where(p=> p.DepartmentAddress.City == "New York)))
.ToList();
Maybe this:
ctx.Employee
.Include( e => e.EmployeeDepartment)
.Include( e => e.EmployeeDepartment.DepartmentAddress)
.Where(e => && e.EmployeeDepartment.DepartmentAddress.All(y => y.City == "New York")).ToList();
"What I'm trying to do is write Entity Framework query, which will return, for example, all employees which are assigned to department in City of New York."
If you're not interested in actually retrieving the departments, and only want to filter by them, then a join would be more appropriate. It's easier for other developers to see that your intention is to narrow down the list of employees, rather than simply narrowing down the list of nested department addresses. This can be accomplished in extension syntax(which I prefer), but joins are much more readable in expression syntax:
var employeesInNewYorkDepartments =
(from employee in ctx.Employee
let department = employee.EmployeeDepartment
let departmentAddress = department.DepartmentAddress
where departmentAddress.City == "New York"
select employee).ToList();
Hopefully I don't have syntax errors. This assumes the relationship from employee to department is many-to-one. I.e. many employees are in a department.
If it's the opposite for both relationships:
var employeesInNewYorkDepartments =
(from employee in ctx.Employee
join department in employee.EmployeeDepartments
join departmentAddress in department.DepartmentAddresses
where departmentAddress.City == "New York"
select employee).Distinct().ToList();
Note your navigation property name should be plural when navigating in the many direction. They represent access to a collection and therefore a singular navigation property name is extremely misleading. (The entity class name would still be singular though as it declares the structure of a single item.)

SQL SELECT depending on multiple variables and tables

I'm trying to create a SELECT query, but the problem here is that I get multiple variables that suitable for different table.
To make it clear I'll present the database tables :
Category
CatID
CatName
Subcategory
CatID
SubCatID
SubCatName
Company
CompanyID
CompName
SubCat
Model
CompID
ModelID
ModelName
Posts
PostID
ModelID
Now, I get some parameters like : Cat, Subcat, Category, ModelID and Name, and what i need is to select all the matching results of PostID that suits for the parameters.
E.g, if I get the following parameters :
Cat = "Electronics"
Subcat="Computers"
Company="Apple"
ModelName="Macbook Air"
Keyword="new"
I need to get the following results of Posts where the category equals to the Cat variables, and the subcategory matches the SubCat Variable and so on.. and in addition to filter the result using %Like% for the keyword variable that I got.
Unfortunately I failed after a lot of tries trying to solve it. Tried using the Inner JOIN in different ways, but it didn't work.
I would really appreciate if someone can help me with this, because I got not idea how to continue form this point, and I don't have a lot of time till I need to finish this project.
Thanks in advance
Select posts.*
from Posts inner join
model on posts.modelId = model.modelId and model.ModelName = 'Macbook Air' inner join
Company on model.compID = company.companyID and Company.CompName = 'Apple' inner join
Subcategory on company.subCat = Subcategory.SubcatID and subcategory.subcatName ='Computers' inner join
Category on subcategory.catID = category.catID and category.CatName = 'Electronics'
where posts.keywordField like '%new%'
I had to make some assumptions there, like what field you are trying to search for your keyword in. But you get the general idea: at each inner join you can specify an additional condition that will limit your results, and in this manner apply your parameters to your query.
One possible way to make this work would be to create a View so you only have one table to search against.
Select c.*, sc.SubCatName, com.*, ModelName, p.*
from Category c
join Subcategory sc on c.CatID = sc.CatID
join Company com on sc.SubCatID = com.SubCatID
join Model m on com.CompID = com.CompID
join Posts p on p.ModelID = m.ModelID

Categories