Search code examples
c#asp.net-web-apilinq-to-entities

Filtering one to many in LINQ to Entities


I have a simple one to many between employees and skills

var bob = new Employee
        {
            Name = "Bob",
            Title = "Senior Developer",
            Skills = new Collection<string> { "ASP.NET", "C#", "JavaScript", "SQL", "XML" }
        };

        var sam = new Employee
        {
            Name = "Sam",
            Title = "Developer",
            Skills = new Collection<string> { "ASP.NET", "C#", "Oracle", "XML" }
        };

var employees = new List<Employee> { bob, sam };

Target

I need all the employees with all skills BUT the C# one .

Attempts

This is the json i get when i just return employees from the web api method

[
  {
    "title": "Senior Developer",
    "name": "Bob",
    "skills": [
      "ASP.NET",
      "C#",
      "JavaScript",
      "SQL",
      "XML"
    ]
  },
  {
    "title": "Developer",
    "name": "Sam",
    "skills": [
      "ASP.NET",
      "C#",
      "Oracle",
      "XML"
    ]
  }
]

My target json would be

[

  {
    "title": "Senior Developer",
    "name": "Bob",
    "skills": [
      "ASP.NET",
      "JavaScript",
      "SQL",
      "XML"
    ]
  },
  {
    "title": "Developer",
    "name": "Sam",
    "skills": [
      "ASP.NET",
      "Oracle",
      "XML"
    ]
  }
]

I have tried performing a selectMany but then I loose the parent employee. I attempted to use the result selector overload of select many but then the desired Employee nesting is lost in the json.

If I perform this

var skills = employees
            .SelectMany(e => e.Skills, (e, s) => new { e.Name, s })
            .Where(empAndSkill => !empAndSkill.s.Equals("C#"));

This is the json I get

[
  {
    "name": "Bob",
    "s": "ASP.NET"
  },
  {
    "name": "Bob",
    "s": "JavaScript"
  },
  {
    "name": "Bob",
    "s": "SQL"
  },
  {
    "name": "Bob",
    "s": "XML"
  },
  {
    "name": "Sam",
    "s": "ASP.NET"
  },
  {
    "name": "Sam",
    "s": "Oracle"
  },
  {
    "name": "Sam",
    "s": "XML"
  }
]

Obviously not what I am trying to achieve. My target appears trivial yet the solution I am attempting at looks complicated which reminds me that perhaps I am missing something or doing something wrong. I have just started with LINQ to Entities a month ago .

Any help?


Solution

  • That you need is to filter out C# from the corresponding collection for each employee. Below we just do a projection of each employee to a new employee having filtered out C# from her skills.

    var employeesWithCSharpFilteredOut = 
               employees.Select(employee => new Employee
               {
                   Name = employee.Name,
                   Title = employee.Title,
                   Skills = employee.Skills
                                    .Where(skill => !string.Equals(skill,"C#",StringComparison.InvariantCultureIgnoreCase))
                                    .ToList()
               }).ToList();