first last first last - 1 month ago 8
C# Question

Behaviour when including the same field twice in entity framework linq

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.

Answer

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 wired thing to do.

Hope this helps!