简体   繁体   中英

Return data from related records with Linq to Entities

I am trying to retrieve records to populate a ListView, using Entity Framework, from three tables.

An example structure of these tables is:

luPersonType

PersonTypeID
PersonTypeDescription

People

PersonID
FirstName
LastName
{...}
PersonTypeID

EmployeeInfo

EmployeeInfoID
PersonnelNumber
StartDate
{...}
PersonID

luPersonType is a lookup table which holds two values ("Customer" and "Employee) used to differentiate types of people. luPersonType has a 1:M relationship to People.

If a person is an Employee, they will have additional details stored about them in the EmployeeInfo table. People has a 1:1 (theoretical) relationship to EmployeeInfo.

Example data:

luPersonType

PersonTypeID----PersonTypeDescription
1---------------Customer
2---------------Employee

People

PersonID----FirstName---LastName---PersonTypeID
1-----------Jane--------Doe--------1
2-----------John--------Doe--------2
3-----------Bob---------Smith------1
4-----------Sue---------Jones------2

EmployeeInfo

EmployeeInfoID----PersonnelNumber----StartDate----PersonID
1-----------------ABC123-------------1/1/13-------2
2-----------------XYZ456-------------2/1/13-------4

As you can see, both John and Sue are Employees and they each have a record in the EmployeeInfo table.

I would like to return a list of all people, with their PersonType description, and EmployeeInfo details (if any):

luPersonType.PersonTypeDescription,
People.LastName + ", " + People.FirstName AS FullName,
EmployeeInfo.PersonnelNumber,
EmployeeInfo.StartDate

This would result in:

PersonTypeDescription----FullName----PersonnelNumber----StartDate
Customer-----------------Doe, Jane---NULL---------------NULL
Employee-----------------Doe, John---ABC123-------------1/1/13
Customer-----------------Smith, Bob--NULL---------------NULL
Employee-----------------Jones, Sue--XYZ456-------------2/1/13

I first tried this code, but it only returned People that had records in both People and EmployeeInfo (inner join?):

using(MyEntities ctx = new MyEntities())
{
    var query = from a in ctx.People
                join b in ctx.luPersonType on a.PersonTypeID equals b.PersonTypeID
                join c in ctx.EmployeeInfo on a.PersonID equals c.PersonID
                orderby a.LastName
                select new
                {
                    b.PersonTypeDescription,
                    FullName = a.LastName + ", " + a.FirstName,
                    c.PersonnelNumber,
                    c.StartDate
                };

    RadListViewPeople.DataSource = query.ToList();
}

Since that seemed to result in an inner join, I looked into different ways to write this query. Here is my second try:

using (MyEntities ctx = new MyEntities())
{
    var query = from a in ctx.People
                orderby a.LastName
                select new
                {
                    a.luPersonType.PersonTypeDescription,
                    FullName = a.LastName + ", " + a.FirstName,
                    PersonnelNumber = from b in a.EmployeeInfos
                                      select b.PersonnelInfo
                    StartDate = from b in a.EmployeeInfos
                                select b.StartDate
                }
}

This returned all four records, but it returned the datatype for PersonnelNumber (System...String) and StartDate (System...DateTime).

I have read about the .Include method, but I haven't been able to get that to work, either.

The second query gave me all the records that I wanted and it seems cleaner to me, but I just can't figure out how to retrieve the actual data values from EmployeeInfo.

Any help will be greatly appreciated!

If your model is setup properly, you should simply be able to do this (note: not tested, so i'm not 100% sure the syntax is correct, but it should give you what you need to solve the problem, i'm also guessing at the name of the navigation property EmployeeInfo):

var query = from a in ctx.People
            let b = a.EmployeeInfo.FirstOrDefault()
            orderby a.LastName
            select new {
                a.luPersonType.PersonTypeDescription,
                FullName = a.LastName + ", " + a.FirstName,
                b.PersonnelNumber,
                b.StartDate
            };

The problem here is the PersonnelInfo is actually 1:many, even though you only use it as a 1:1, so you have to select the first record or Default to return null if no association.

Note: this only works when using IQueryable, because EF does not treat null references as problems. If this were converted to an IEnumerable, then the code above would throw an execption on PersonnelNumber and StartDate because b would be null for some records.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM