Создание динамического запроса linq - PullRequest
4 голосов
/ 12 мая 2010

У меня следующий запрос:

from p in dataContext.Repository<IPerson>()
     join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
     join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
     join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
     join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id
     where s1.Name == "Soccer" && s2.Name == "Tennis"
     select new { p.Id };

Он выбирает всех, кто играет в футбол и теннис.
Во время выполнения пользователь может выбрать другие теги для добавления в запрос, например: «Хоккей». теперь мой вопрос, как я могу динамически добавить «Хоккей» к запросу? Если к запросу добавлено «Хоккей», это будет выглядеть так:

from p in dataContext.Repository<IPerson>()
     join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
     join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
     join spp2 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp2.PersonId
     join s2 in dataContext.Repository<ISports>() on spp2.SportsId equals s2.Id  
     join spp3 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp3.PersonId
     join s3 in dataContext.Repository<ISports>() on spp3.SportsId equals s3.Id
     where s1.Name == "Soccer" && s2.Name == "Tennis" && s3.Name == "Hockey"
     select new { p.Id };

Было бы предпочтительнее, если запрос создается динамически, например:

private void queryTagBuilder(List<string> tags)
{
    IDataContext dataContext = new LinqToSqlContext(new L2S.DataContext());
    foreach(string tag in tags)
    {
        //Build the query?
    }
}

У кого-нибудь есть идея, как правильно это настроить? Заранее спасибо!

Ответы [ 2 ]

3 голосов
/ 12 мая 2010

Запрос LINQ не анализируется до тех пор, пока он фактически не будет выполнен. Таким образом, вы можете сделать что-то вроде этого:

var q = from r in ctx.records 
         /* Do other stuff */
         select r;

if (!string.IsNullOrEmpty(search)) {
  q = from r in q
       where r.title == search
       select r;
}

if (orderByName) {
  q = q.OrderBy(r => r.name);
}

/* etc */

это создаст одну выполняемую инструкцию SQL.

По вашему конкретному вопросу: объединения делают его несколько сложным, но я думаю, что вы можете объединиться с другими «динамическими» запросами.

Итак, вы бы получили что-то вроде этого:

var baseQ = from p in dataContext.Repository<IPerson>()
            select p;
foreach(var tag in tags) {
   baseQ = from p in baseQ 
     join spp1 in dataContext.Repository<ISportsPerPerson>() on p.Id equals spp1.PersonId
     join s1 in dataContext.Repository<ISports>() on spp1.SportsId equals s1.Id
     where s1.name == tag
     select p;
}

/* If you have defined your relations correct, simplify to something like this.
   Does not actually work because of SportsPerPerson probably has multiple sports: */
foreach(var tag in tags) {
   baseQ = baseQ.Any(p => p.SportsPerPerson.Sports.Name == tag); 
}


var resultQ = from p in baseQ
     select new { p.Id };
2 голосов
/ 12 мая 2010

Я и мой коллега нашли решение, и мы реорганизовали запрос, чтобы он работал правильно. Теперь мы используем следующий запрос для получения правильного набора результатов:

var query = dataContext.Repository<ILead>();

        foreach (var tag in tags)
        {
            String tagName = tag;
            query = query.Where(l => dataContext.Repository<ISportsPerPerson>()
                         .Any(tpl => tpl.PersonId.Equals(l.Id) && tpl.Sports.Name.Equals(tagName)));
        }
// Do something with query resultset :]
...