1
    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.

FrostyStraw
  • 1,628
  • 3
  • 25
  • 34
  • It's adding an additional check to ensure that the school's ID is in the `schoolsList` list. _Why_ it's doing that is unknown. – D Stanley Jul 22 '15 at 16:43
  • @DStanley but how is it getting a school id to pass into the Contains method? Also, when I get rid of the this.schoolList.Contains() condition, a Team object is actually returned (with a school id). But when the condition is there, the Team object returned is null. Why would that be? – FrostyStraw Jul 22 '15 at 16:44
  • Change your question text and add double newlines to split paragraphs. – Croll Jul 22 '15 at 16:45

3 Answers3

2

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 ;-)

Community
  • 1
  • 1
Philip Stuyck
  • 7,344
  • 3
  • 28
  • 39
  • I'm still trying to figure out how to get the SQL generated, but I have a further question. My Team object is being returned as null. I know it's not because of the x.id == id condition because the id parameter matches the id property of the Team object, so it must be the this.schoolList.Contains(x.school_id) condition that is not working. Does the fact that it returns null mean that the school id of the Team object was not found in schoolList? – FrostyStraw Jul 22 '15 at 17:20
  • yes but you can capture the generated sql and use sql server management studio to paste the query. You can then manipulate it to figure out what is going on. Based on what you say the schoollist is blocking the return value. remove the contains, if values are returned you also have confirmation. – Philip Stuyck Jul 22 '15 at 17:31
  • I just found that my schoolList isn't populated for some reason, so that must be the problem – FrostyStraw Jul 22 '15 at 17:50
  • yes that would make the query not return anything at all. – Philip Stuyck Jul 22 '15 at 17:58
2
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;
    }
}
Leandro Soares
  • 2,902
  • 2
  • 27
  • 39
  • 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 Jul 22 '15 at 17:08
  • I don't get what you meant to explain with the ah! ... What follows is logically what is going on but the query is executed at the server and translates into an in clause. Your edit makes your answer worse than without it. You are definitely not calling the schoolist on each iteration because the sql generated does not have a schoollist anymore it has an expanded in clause containing the schoolids in the list). Sql server uses set logic to process such a query very quickly. – Philip Stuyck Jul 22 '15 at 17:36
  • @PhilipStuyck his update made me feel like I understood what was going on a little better, although your comment to it now makes me question that. – FrostyStraw Jul 22 '15 at 17:49
  • Sql server uses set logic whereas C# is procedural logic. Sql server is good at set logic and this kind of logic is executed many times faster than any procedural logic would. – Philip Stuyck Jul 22 '15 at 17:57
1

.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.

Croll
  • 3,631
  • 6
  • 30
  • 63