I've implemented an Table Inheritance functionality demonstrated at http://www.sqlteam.com/article/implementing-table-inheritance-in-sql-server.
All the foreign keys and constraints are in place.
Now I am using Entity Framework to pull back my People, Students, Teachers, and Parents where the model looks something like the following (without all the EF specific attributes etc).
public partial class People : EntityObject
{
public guid PeopleID { get; set; }
public int Age { get; set; } /Added for an example query
public PeopleParent Parent { get; set; }
public PeopleStudent Student { get; set; }
public PeopleTeacher Teacher { get; set; }
}
Now I need to get all People regardless of type, who are 25 years old, no more than 100 records, and I want to include all the referenced data. I create my EF Query like:
IQueryable<People> query = Entities.People.Include("PeopleParent")
.Include("PeopleStudent")
.Include("PeopleTeacher");
query.Where(x => x.Age == 25)
.Take(100);
IEnumerable<People> results = query.ToList();
Seems simple enough, but whatever table/entityset I've set to include first creates an INNER JOIN
instead of the LEFT OUTER JOIN
, which is not producing the right results.
Generated TSQL (incorrect for my needs):
SELECT
[Limit1].[C1] AS [C1],
<A bunch of Limit1 Columns>
FROM (
SELECT TOP (100)
[Extent1].[PeopleID] AS [PeopleID],
<A bunch of Extent1 Columns>
[Extent2].[PeopleID] AS [PeopleID1],
<A bunch of Extent2 Columns>
[Extent3].[PeopleID] AS [PeopleID2],
<A bunch of Extent3 Columns>
[Extent4].[PeopleID] AS [PeopleID3],
<A bunch of Extent4 Columns>
1 AS [C1]
FROM [rets].[People] AS [Extent1]
INNER JOIN [rets].[PeopleParent] AS [Extent2]
ON [Extent1].[PeopleID] = [Extent2].[PeopleID]
LEFT OUTER JOIN [rets].[PeopleStudent] AS [Extent3]
ON [Extent1].[PeopleID] = [Extent3].[PeopleID]
LEFT OUTER JOIN [rets].[PeopleTeacher] AS [Extent4]
ON [Extent1].[PeopleID] = [Extent4].[PeopleID]
) AS [Limit1]
Why is the first Include used as an INNER JOIN
, and is there a soluion to my problem?
** UPDATE 1**
Assuming I use Ladislav Mrnka's Answer, there are two additional requirements due to the significant change in Linq and Lambda querying.
Question: How do I search for specific People which have specific properties?
(All Students with a Grade of "A")
Answer:
context.People.OfType<Student>().Where(s => s.Grade == "A");
Question: How do I search for any People that have a specific property?
(All Students or Teachers who's PrimaryFocus = "Math")
Answer:
List<People> result = new List<People>();
result.AddRange(context.People.OfType<Student>()
.Where(x => x.PrimaryFocus == "Math")
.ToList());
result.AddRange(context.People.OfType<Teacher>()
.Where(x => x.PrimaryFocus == "Math")
.ToList());