Get Specific object after a join using LINQ - c#

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();

Related

C# & Entity Framework : return specific columns from a 3 table join

I have a C# application where I am using Entity Framework to pull data from a database. This is the code I am executing:
var person = new List<Person>();
using (DevTestEntities db = new DevTestEntities())
{
person = (from p in db.People
join e in db.PersonEmails on p.Id equals e.Id
join t in db.PersonPhones on p.Id equals t.Id
where t.Phone == phoneNumber
select p).ToList();
}
var str = Newtonsoft.Json.JsonConvert.SerializeObject(person);
return str;
When the code runs, it fails on the select. I assume it is failing because there is a table within the database that is not part of the model. And because there is just a generic select, I assume Entity Framework is selecting all columns from all tables and doesn't know what to do with some of the columns.
What I really want to do is to be able to specify the columns that I want to return to the calling function. How do I specify what columns Entity Framework should select?
Thanks for any assistance.
EF will not fail because of tables in the DB that are not in model. It would help if you provided the error. Also, your query will result in selecting all columns from the People table but not the others.
An example answer to your question is this, it selects three columns from different tables and puts them in a new anonymous type:
var onlySomeColumns = (from p in db.People
join e in db.PersonEmails
on p.Id equals e.Id
join t in db.PersonPhones
on p.Id equals t.Id
where t.Phone == phoneNumber
select new {p.Id, e.email, t.phonenumber}).ToList();

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

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!

Use multiple left joins to set DTO property inside select new linq query

I have the following code inside an MVC 6 (beta8) controller:
public IActionResult Get()
{
var districtsdetails = from districts in _ctx.District
select new
{
Id = districts.Id,
CountyFP = districts.County.FIPSCode,
DirectorName = districts.DirectorName,
Email = districts.Email,
EstStudentPop = districts.EstStudentPop,
Name = districts.Name,
Phone = districts.Phone,
Ranking = districts.Ranking,
RANumber = districts.RANumber,
SchoolCount = districts.SchoolCount,
Coop = districts.Coop.Name,
County = districts.County.Name,
Distributors = (from district in _ctx.District
join districtdistributor in _ctx.DistrictDistributor on district.Id equals districtdistributor.DistrictId
into group1
from g1 in group1.DefaultIfEmpty()
join distributor in _ctx.Distributor on g1.DistributorId equals distributor.Id
into group2
from g2 in group2.DefaultIfEmpty()
where district.Id == districts.Id
select new { g2.Id, g2.Name })
};
if (districtsdetails == null)
return HttpNotFound();
return new JsonResult(districtsdetails);
}
The problem is in the Distributors property setter.
I have District, DistrictDistributor, and Distributor entities in my context (and matching tables in my db). There is a many to many relationship between District and Distributor, with DistrictDistributor mapping the many to many relationship between the two. In my DistrictDetailsDTO I'm attempting to bridge the DistrictDistributor gap so I can just do DistrictDetailsDTO.Distributors ... All this is being serialized to Json as you can see by the JsonResult().
In the Distributor = (...) I am trying to effectively reproduce this SQL:
select (...)
from [District] D
left join [DistrictDistributor] DD on
DD.DistrictId = D.Id
left join [Distributor] Db on
Db.Id = DD.DistributorId
where id = 57
However, in my linq 57 would be districts.Id since I'm returning all Districts.
Please HELP I'm going CRAZY! No matter what I try along these lines produces a:
HTTP Error 502.3 - Bad Gateway
The specified CGI application encountered an error and the server terminated the process.
Here is how I think it could be resolved.
First, your query - the hard way. You don't need left joins here at all. They would be needed if you were producing a joined result set (SelectMany), but since that's not the case, you can use the following and let EF do it's magic to make it work:
var query =
from district in _ctx.District.AsNoTracking()
select new
{
Id = district.Id,
Name = district.Name,
// the rest of the district related fields
// ...
Distributors =
from dd in _cxt.DistrictDistributor
where dd.DistrictId == district.Id
join d in _ctx.Distributor on dd.DistributorId equals d.Id
select new { d.Id, d.Name }
};
Second - the easy way. One of the cool things of EF is to describe your model with navigation properties and properly configured relationships. This way you can almost forget about manual joins and let EF do whatever is necessary to satisfy your queries. In your case, the proper model would have District.Distributors and Distributor.Districts navigation properties, and the same result could be achieved with the following simple query:
var query =
from district in _ctx.District.AsNoTracking()
select new
{
Id = district.Id,
Name = district.Name,
// the rest of the district related fields
// ...
Distributors = district.Distributors.Select(d => new { d.Id, d.Name })
};

Linq to Entities (EF): How to get the value of a FK without doing the join

I'm using the Linq to Entities. I've got my main table, Employee setup with a field named vendorID. Vendor ID is a foreign key into the Vendors table.
As it is right now, the Employee object does not directly expose the vendorID. Instead, I can only access it this way:
var employee = (from e in context.Employees.Include("tbl_vendors")
where e.employeeID = 1
select e).FirstOrDefault();
//this gets the vendor ID
int vendorID = employee.tbl_vendors.vendorID;
That is just fine and dandy, but it is extra work on the database because it is forcing a join where none is needed. Is there a way to get that key value without being forced to do a join to the tbl_vendors table?
Actually this is very simple you basically do this:
var tblVendorID = (from e in context.Employees
select e.tbl_vendors.ID).FirstOrDefault();
Even though this looks like you are doing a join L2E will optimize out the join.
Which you can confirm with code like this:
var results = from e in ctx.Employees
select e.tbl_vendors.ID;
var query = results as ObjectQuery<int>;
string sql = query.ToTraceString();
Hope this helps
Alex (Microsoft).
You can access the foreign key via the entity reference.
Employee employee = context.Employees.Single(e => e.employeeID == 1);
Int32 vendorID = (Int32)employee.tbl_vendorsReference.EntityKey.
EntityKeyValues[0].Value;
See MSDN for reference on the EntityReference and EntityKey classes.
Not sure about your object names here but you can grab the key from the entity key property without going to the database something like this:
var employee = (from e in context.Employees
where e.employeeID = 1
select e).FirstOrDefault();
//this gets the vendor ID
int vendorID = (int)employee.tbl_vendorsReference.EntityKey.EntityKeyValues[0].Value;

Linq to Sql - Populate JOIN result into a List

I am not sure if this can be done, but here's the scenario.
I want to turn this sql into linq:
SELECT * FROM Department d
INNER JOIN Employee e ON e.DepartmentID = d.DepartmentID
Department - Employee is 1 to many relationship.
I have created a custom object that I would like to populate the result into.
public class DepartmentSummary
{
public Department Department { get; set; }
public List<Employee> Employees {get; set;}
}
The Linq I came up with is
var result = from d in dba.Department
join e in dba.Employee d.DepartmentID equals e.DepartmentID into j1
select new DepartmentSummary
{
Department = d,
Employees = j1.ToList()
};
I tried it out and it's not working. Can anyone shed some light for me please? I would like to perform an inner join between Department and Employee. For each Department in the resultset, I would like to create one DepartmentSummary object which holds that department and a list of employees belonging to that department.
Does Linq provides an ad hoc solution for this or must I iterates through the result set and create a list of DepartmentSummary manually?
Thanks,
EDIT:
Looks like this works for me
var result = from d in dba.Department
join e in dba.Employee d.DepartmentID equals e.DepartmentID into j1
where j1.Count() > 0
select new DepartmentSummary
{
Department = d,
Employees = j1.ToList()
};
The thing is that you're not really taking one SQL and trying to create a Linq-query out of it.
If you were, you'd notice that your SQL query does not really produce one row per department, but it will repeat the department information for each employee in that department.
Now, an initial naive look would suggest you use a group-by clause, since that would allow you to split the data into individual groupings for each department, but groupings in SQL does not really give you a key+all-matching-rows type of result, rather it allows you to do aggregate calculations, like "for each department, how many employees do I have".
So, in order to do what you want, you need to basically do a normal join, which will give you each employee, coupled with the appropriate department information (ie. each employee will be linked to his/her department), and then you need to construct the rest of the data structure yourself.
Now, having said that, if you have the proper relationships set in your data context related classes, each department should already have some kind of property that contains all employees in that department, so perhaps the simple query is just "give me all departments", and then you can, for each department, retrieve the employees?
Of course, doing that would likely execute one SQL for each department, but in this case, you're back to "give me all employees with their department information" and you have to build code to handle the rest.
LINQ to SQL doesn't understand your ToList() call, but you might be able to select the sequence of joined elements and then use LINQ to Objects (via AsEnumerable()) to map to your DepartmentSummary object:
var qResult = from d in dba.Department
join e in dba.Employee d.DepartmentID equals e.DepartmentID into j1
select new
{
Department = d,
Employees = j1
};
var result = from d in qResult.AsEnumerable()
select new DepartmentSummary()
{
Department = d.Department,
Employees = e.Employees.ToList()
};
Sounds like you're looking to get around lazy loading?
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Department>(d => d.Employees);
using (var dba = new MyDataContext())
{
dba.LoadOptions = dlo;
var result = from d in dba.Department
select d;
}
Now, if you don't have a relationship defined between Department and Employees (the Linq2Sql designer will do this for you if you have database relationships setup) then you should look into doing that. It makes it all dramatically easier. In fact, you don't even need your campaign summary.
This problem is due to the nature of the query. When you join Department to Employee, you'll get back one record for every Employee. This means that your ToList() statement is expecting multiple employees per department, but due to the join, always getting one.
Change your query to
var result =
from d in dba.Department
select new tCampaignSummary
{
Department = d,
Employees = dba.Employee.Where(e => e.DepartmentID ==
d.DepartmentID).ToList()
};
I've tested this and it works.
What it does differently is selects only one record per Department (not per employee) then it gets the zero to many corresponding employees for each dept and converts them to a list.
Good luck!
EDIT
As requested, here is the generated SQL:
SELECT [t0].*, [t1].*
(
SELECT COUNT(*)
FROM [dbo].[Employee] AS [t2]
WHERE [t2].[DepartmentID] = [t0].[DepartmentID]
) AS [value]
FROM [dbo].[Department] AS [t0]
LEFT OUTER JOIN [dbo].[Employee] AS [t1]
ON [t1].[DepartmentID] = [t0].[DepartmentID]
ORDER BY [t0].[DepartmentID], [t1].[IndexID]
The only modification is that LINQ will not do [t0].*, instead it will enumerate each field. Since I had to guess at the fields, I left them out to make the SQL clearer.

Categories