FrostyStraw
FrostyStraw

Reputation: 1656

Can someone help me understand the following line?

    public Team getTeamByID(int id)
      {
    Team team = ctx.Teams.Include("Login").Include("People").Include("School").Where(x => x.id == id && this.schoolsList.Contains(x.school_id)).FirstOrDefault();

          ///

       }

ctx is a DataAccess obbject and schoolsList is a DataAccess property of type List. I understsand the part that says x => x.id == id, but the part where this.schoolsList.Contains(x.school_id) makes no sense to me. I know x => x.id == id returns Team objects that match the id passed in as an argument, but how exactly does this.schoolsList.Contains(x.school_id) work? How can I be able to use school_id property (which is a property of the Team class)?

Is the first part of the predicate (x => x.id == id) returning the Team Object, and then the second part is using the returned object's school id? For some reason that seems like a weird way for things to be working since I kinda thought everything in the Where() method taken together returned something, instead of each condition returning something.

Upvotes: 1

Views: 65

Answers (3)

Leandro Soares
Leandro Soares

Reputation: 2972

Team team = ctx.Teams
               .Include("Login")
               .Include("People")
               .Include("School")
               .Where(x => x.id == id 
                           && this.schoolsList.Contains(x.school_id))
               .FirstOrDefault();

With this line you are retrieving the first element of ctx.Teams that meets the requirements imposed by the Where clause

ctx.Teams

Here you calling the table Teams from the database through ctx

The Include statements are used to join other tables like a Join in SQL and retrieves the data within the joined table.

.Where(x => x.id == id 
            && this.schoolsList.Contains(x.school_id))

Here you are filtering the table data where the line has the id from the variable id and is inside schoolsList.

FirstOrDefault(); this retrieves the first item inside the IQueryable returned by the Where clause.

This can also be translated to:

Team team = ctx.Teams
               .Include(x => x.Login)
               .Include(x => x.People)
               .Include(x => x.School)
               .FirstOrDefault(x => x.id == id
                           && this.schoolsList.Contains(x.school_id));

Includes written like this are less buggy like and more OOP. To do this you need the following namespace System.Data.Entity.

** EDIT 1 **

I sort of understand but not completely. How does it know what x.school_id is? I thought I had included it in my question, but I just edited it in, and the only argument passed into that function was "id." So where exactly is the value of x.school_id passed into Contains coming from? Is it from the Team object that is returned from the condition x.id == id? – FrostyStraw

Because the Where clause or FirstOrDefault does a iteration with SQL through ctx.Teams where the class of Teams contains the property school_id.

This is only possible with EntityFramework, where a table is represented by a class and the class properties are table Columns.

Ah! and when you do this.schoolsList.Contains(x.school_id) you are calling the list schoolsList on each "SQL Iteration" caused by Where.

It's like doing:

List<Team> teams = ctx.Teams
       .Include("Login")
       .Include("People")
       .Include("School")
       .ToList();

Team team = null;
foreach (var item in teams)
{
    if (item.id == id && this.schoolsList.Contains(item.school_id))
    {
        team = item;
        break;
    }
}

Upvotes: 2

Croll
Croll

Reputation: 3791

.Can someone help me understand the following line?

It does invoke Include() method several times, which returns this (same object), so it can invoke it again.

Then it uses LINQ query (seems IEnumerable<> inherited) to find specific element by condition in lambda.

FirstOrDefault() returns first matching element (if any) or null (default(T)). Answering your original question.

Lambda condition is a simple if expression for IEnumerable items. Lambda gets invoked to return true or false each time FirstOrDefault() will enumerate internal array to determine if item matches or not.

Upvotes: 1

Philip Stuyck
Philip Stuyck

Reputation: 7447

The contains method is translated into SQL with the IN clause. suppose the list contains 3 items 1,2,3 then it translates into

 where team.school_id in (1,2,3)

Take a look at the generated sql, for instance intellisense shows it if you have VS ultimate, and things will become understandable. Otherwise look at this How do I view the SQL generated by the Entity Framework?

I have done this with an example of myself :

 string[] roles = {"admin","medewerker"};       
        _medewerkers = contactPersoonRepository
            .Query(c => c.Bedrijf.BEDRIJF_TYPE.Contains("P") && roles.Contains(c.CP_ROLE))
            .NoTracking()
            .OrderBy(q => q.OrderBy(d => d.CP_NAAM))
            .Select(b => new Medewerker
            {
                Naam = b.CP_NAAM,
                VoorNaam = b.CP_VOORNM,
                Id = b.CP_CPID,
                Rol = b.CP_ROLE,
                Uurloon = b.CP_UURLOON
            }).ToList();

translates into

USE [Jogical];

GO

SELECT 
[Extent1].[CP_CPID] AS [CP_CPID], 
[Extent1].[CP_NAAM] AS [CP_NAAM], 
[Extent1].[CP_VOORNM] AS [CP_VOORNM], 
[Extent1].[CP_ROLE] AS [CP_ROLE], 
[Extent1].[CP_UURLOON] AS [CP_UURLOON]
FROM  [dbo].[ContactPersoon] AS [Extent1]
INNER JOIN [dbo].[Bedrijf] AS [Extent2] ON [Extent1].[CP_BEDRIJFID] = [Extent2].[BEDRIJF_ID]
WHERE ([Extent2].[BEDRIJF_TYPE] LIKE N'%P%') AND ([Extent1].[CP_ROLE] IN (N'admin', N'medewerker')) AND ([Extent1].[CP_ROLE] IS NOT NULL)
ORDER BY [Extent1].[CP_NAAM] ASC

The relevant part is this :

([Extent1].[CP_ROLE] IN (N'admin', N'medewerker'))

Which comes from the contains call.

Notice how the contains is translated differently when applied on a string. Isn't EF great ;-)

Upvotes: 2

Related Questions