简体   繁体   中英

How to perform a Linq2Sql query on the following dataset

I have the following tables:

Person(Id, FirstName, LastName)
{
    (1, "John", "Doe"),
    (2, "Peter", "Svendson")
    (3, "Ola", "Hansen")
    (4, "Mary", "Pettersen")
}

Sports(Id, Name)
{
    (1, "Tennis")
    (2, "Soccer")
    (3, "Hockey")
}

SportsPerPerson(Id, PersonId, SportsId)
{
    (1, 1, 1)
    (2, 1, 3)
    (3, 2, 2)
    (4, 2, 3)
    (5, 3, 2)
    (6, 4, 1)
    (7, 4, 2)
    (8, 4, 3)
}

Looking at the tables, we can conclude the following facts:
John plays Tennis
John plays Hockey
Peter plays Soccer
Peter plays Hockey
Ola plays Soccer
Mary plays Tennis
Mary plays Soccer
Mary plays Hockey

Now I would like to create a Linq2Sql query which retrieves the following:

Executing the query should return: Peter and Mary
Anyone has any idea's on how to approach this in Linq2Sql?

One of the great things about Linq is that you don't HAVE to write this all as one monolithic query because it won't actually execute until you enumerate the results anyway. You could write a single query, but you don't have to. Instead, you can write this as multiple, separate queries, increasing the readability, and clarifying your intent.

var sportIds = Sports
    .Where(s => s.Name == "Hockey" || s.Name == "Soccer")
    .Select(s => s.Id);

var people = Person.Where(p => SportsPerPerson
    .Count(spp => (spp.PersonId == p.Id) 
    && sportIds.Contains(spp.SportId)) == 2);

First, we get the collection of sport Ids we're interested in. Then, we find all the people with two sports in the first list. Although it's expressed as multiple queries, Linq will compress it all into one operation for us when we finally enumerate the results.

EDIT: Here is a complete test class illustrating the query:

using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace L2STest
{
    public class Sport
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class SportPerPerson
    {
        public int Id { get; set; }
        public int PersonId { get; set; }
        public int SportId { get; set; }
    }

    [TestClass]
    public class SportsTest
    {
        private List<Person> persons;
        private List<Sport> sports;
        private List<SportPerPerson> sportsPerPerson;

         [TestInitialize]
         public void MyTestInitialize()
         {
             persons = new List<Person>
             {
                 new Person {Id = 1, FirstName = "John", LastName = "Doe"},
                 new Person {Id = 2, FirstName = "Peter", LastName = "Svendson"},
                 new Person {Id = 3, FirstName = "Ola", LastName = "Hansen"},
                 new Person {Id = 4, FirstName = "Marv", LastName = "Petterson"},
             };

             sports = new List<Sport>
             {
                 new Sport {Id = 1, Name = "Tennis"},
                 new Sport {Id = 2, Name = "Soccer"},
                 new Sport {Id = 3, Name = "Hockey"},
             };

             sportsPerPerson = new List<SportPerPerson>
             {
                 new SportPerPerson {Id = 1, PersonId = 1, SportId = 1}, 
                 new SportPerPerson {Id = 2, PersonId = 1, SportId = 3}, 
                 new SportPerPerson {Id = 3, PersonId = 2, SportId = 2}, 
                 new SportPerPerson {Id = 4, PersonId = 2, SportId = 3}, 
                 new SportPerPerson {Id = 5, PersonId = 3, SportId = 2}, 
                 new SportPerPerson {Id = 6, PersonId = 3, SportId = 1}, 
                 new SportPerPerson {Id = 7, PersonId = 4, SportId = 2}, 
                 new SportPerPerson {Id = 8, PersonId = 4, SportId = 3}, 
             };
         }

        [TestMethod]
        public void QueryTest()
        {
            var sportIds = sports
                .Where(s => s.Name == "Hockey" || s.Name == "Soccer")
                .Select(s => s.Id);

            var people = persons.Where(p => sportsPerPerson
                .Count(spp => (spp.PersonId == p.Id)
                && sportIds.Contains(spp.SportId)) == 2); 

            Assert.AreEqual(2, people.Count());
            Assert.AreEqual("Peter", people.First().FirstName);
            Assert.AreEqual("Marv", people.Last().FirstName);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM