6

what happens when I include the same field twice, meaningly I take from db an entity and I use the EF .include option. What I mean is this:
I have:

.Include(x => x.Student)
.Include(x => x.Car)
.Include(x => x.Student)

This is the model:

Person has a Student
Person has a car

so by including (by mistake) the student twice (since my person has ONLY a student), is there an issue?
P.S. I only want it included ONCE! since I have only a single student. Does ef complain about this? I tried it and it seemed ok, but I do not know the implications of this. Can anyone explain/elaborate? Searched a bit but couldn't identify any issues.

first last
  • 63
  • 6
  • I believe there should not be any issues, and you are *supposed* to use it like that in fact. I'll try to find the documentation on it. – Zack Oct 26 '16 at 15:07
  • My point is that I need ONLY a student. The base entity is a person, therefore it has a single student. – first last Oct 26 '16 at 15:17

3 Answers3

5

Take this sample:

public class RentContext : DbContext
{
    public DbSet<Student> Students { get; set; }

    public DbSet<Rent> Rents { get; set; }

    public DbSet<Car> Cars { get; set; }
}

public class Car
{
    public int Id { get; set; }

    public string Model { get; set; }

    public double Price { get; set; }
}

public class Rent
{
    public int Id { get; set; }

    public Student Student { get; set; }

    public Car Car { get; set; }
}

public class Student
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int Year { get; set; }
}

A rent contains the Student and the Car.

Lets make a query with unique Include clauses:

var rents = ctx.Rents
    .Include(x => x.Student)
    .Include(x => x.Car)
    //.Include(x => x.Student)
    .ToList();

This is the generated sql:

SELECT
[Extent1].[Id] AS [Id],
[Extent2].[Id] AS [Id1],
[Extent2].[Name] AS [Name],
[Extent2].[Year] AS [Year],
[Extent3].[Id] AS [Id2],
[Extent3].[Model] AS [Model],
[Extent3].[Price] AS [Price]
FROM   [dbo].[Rents] AS [Extent1]
LEFT OUTER JOIN [dbo].[Students] AS [Extent2] ON [Extent1].[Student_Id] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Cars] AS [Extent3] ON [Extent1].[Car_Id] = [Extent3].[Id]

Let's make a query duplicating an Include:

var rents = ctx.Rents
    .Include(x => x.Student)
    .Include(x => x.Car)
    .Include(x => x.Student)
    .ToList();

You'll get this sql:

SELECT
[Extent1].[Id] AS [Id],
[Extent2].[Id] AS [Id1],
[Extent2].[Name] AS [Name],
[Extent2].[Year] AS [Year],
[Extent3].[Id] AS [Id2],
[Extent3].[Model] AS [Model],
[Extent3].[Price] AS [Price]
FROM   [dbo].[Rents] AS [Extent1]
LEFT OUTER JOIN [dbo].[Students] AS [Extent2] ON [Extent1].[Student_Id] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Cars] AS [Extent3] ON [Extent1].[Car_Id] = [Extent3].[Id]

As you can see, EF is smart enough to generate the same sql even when you specify an Include more than once.

UPDATE: Repeated includes (many times)

Let's try this:

var rents = ctx.Rents
    .Include(x => x.Student)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Car)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .Include(x => x.Student)
    .ToList();

Repeated Includes and several times. And here's the generated sql:

SELECT
    [Extent1].[Id] AS [Id],
    [Extent2].[Id] AS [Id1],
    [Extent2].[Name] AS [Name],
    [Extent2].[Year] AS [Year],
    [Extent3].[Id] AS [Id2],
    [Extent3].[Model] AS [Model],
    [Extent3].[Price] AS [Price]
    FROM   [dbo].[Rents] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Students] AS [Extent2] ON [Extent1].[Student_Id] = [Extent2].[Id]
    LEFT OUTER JOIN [dbo].[Cars] AS [Extent3] ON [Extent1].[Car_Id] = [Extent3].[Id]

Just the same code again. So, yes. We could say it'll be ok, although a little weird thing to do.

Hope this helps!

Karel Tamayo
  • 3,690
  • 2
  • 24
  • 30
  • So even if I would include the same entity 30 times (like: `.Include(x => x.Student)`, ef would include it only once and generate the corresponding sql with student included only once? – first last Oct 26 '16 at 15:21
  • @firstlast Indeed! Let's try it out. Check the update. – Karel Tamayo Oct 26 '16 at 15:24
  • Thank you! This is a great answer, really on the point of it. And if for the student I want to include the university, can I do `.Include(x => x.Student).Include(x => x.Student.University)` or can I simply go for a single include, meaningly `.Include(x => x.Student.University)`? Note that all the fields from the Student need to be included, but not all the entities (I do need University). – first last Oct 26 '16 at 15:27
  • 1
    When I'll reach rep, I will also up. – first last Oct 26 '16 at 15:27
  • @firstlast you just need to do .Include(x => x.Student.University) and EF will Join with University also. – Karel Tamayo Oct 26 '16 at 15:40
  • Great. So it does actually do the join with student and then a join with university. Was not sure and when I checked, I saw no difference, but I tought of external impacts – first last Oct 26 '16 at 15:57
  • 1
    I appreciate your testing. We have a class with two dbsets. One has includes already in it and the other doesn't. I have a permissions filter that needs three includes and thanks to you all i needed to do was add them in my check without worrying that it would conflict with existing includes. – John Lord May 06 '21 at 21:11
2

If you call it twice, the same query will be generated. Result the same, something like this

SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[Title] AS [Title],
    [Extent1].[PersonId] AS [PersonId],
    [Extent2].[Id] AS [Id1],
    [Extent2].[Name] AS [Name]
    FROM  [dbo].[Books] AS [Extent1]
    INNER JOIN [dbo].[People] AS [Extent2] ON [Extent1].[PersonId] = [Extent2].[Id]
Grigor Aleksanyan
  • 540
  • 1
  • 6
  • 19
1

That is perfectly valid and won't trip up EF in anyway. Consider how you include additional references and collections that hang off a reference like Student. You might write them like this. What you have proposed won't confuse EF any more than the following example.

.Include(x => x.Student.Teacher)
.Include(x => x.Car)
.Include(x => x.Student.DrivingLog)
Jeremy Cook
  • 20,840
  • 9
  • 71
  • 77