2010-07-28 3 views
2

Предположим, у меня есть две таблицы TableA и TableB. Каждая запись в A имеет одну или несколько связанных записей в B. Скажем, я хочу использовать фильтр многократного использования с использованием предикатов. Я мог бы сделать что-то вроде этого (Linq-на-SQL, кстати):DRY LINQ Предикатные фильтры для нескольких таблиц

private Expression<Func<ARecord, bool>> FilterPredicate() 
{ 
    return x => x.Name == "Test"; 
} 

private IQueryable<ARecord> GetRecords() 
{ 
    return DataContext.TableA.Where(FilterPredicate()); 
} 

Это прекрасно работает, но сказать, что я хотел искать TableB, но использовать один и тот же «фильтр» на внешнем ключе. Я хочу выполнить запрос ниже, не переписывая FilterPredicate, как он относится к TableB.

var query = from b in DataContext.B 
      where b.A.Name == "Test" 
      select b; 

Я просто интересно, если есть какие-либо рекомендации по созданию многоразового использования «где» положения, которые могли бы помочь по нескольким таблицам.

Редактировать - Чтобы уточнить, я не ищу способ применить предикат к типам ARecord и BRecord. Я ищу способ (какой-либо образом, не обязательно вдоль линии я уже думал), чтобы предотвратить необходимость этого предиката, а также:

private Expression<Func<BRecord, bool>> FilterPredicate2() 
{ 
    return x => x.A.Name == "Test"; 
} 

Спасибо заранее.

ответ

0

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

var query = from b in DataContext.B 
      select b; 

И применить это к нему:

x => x.A.Name == "Test" 

без необходимости иметь дубликат этого предикат, который я использую при запуске запроса на в таблица:

x => x.Name == "Test" 

так что я полагаю, что решение заключается в «обратном» запрос, начиная от стола, например, так:

var query = from a in DataContext.A 
      join b in B on a equals b.A 
      select b; 

query = query.Where(FilterPredicate()); 

Я думал, что он может переписать запросы неэффективно, но это, похоже, не так.

3

Вы можете сделать это путем определения интерфейса через A и B.

public interface IHasName // contrived, I know 
{ 
    string Name {get;} 
} 

LINQ-to-SQL классы являются неполными, так что в вашей части определения частичного класса, вы можете добавить интерфейс, как так :

public partial class A : IHasName {} 
public partial class B : IHasName {} 

Как вы видите, нет реализации не должно быть необходимым, поскольку свойство Name реализуется в Linq-To-Sql генерироваться части.

Теперь ограничить свой предикат типов, реализующих интерфейс IHasName, и вы все сделали:

private Expression<Func<T, bool>> FilterPredicate(string name) where T : IHasName 
{ 
    return x => x.Name == name; 
} 

теперь вы должны даже быть в состоянии определить метод расширения на IQueryable так:

public static T GetByName<T>(this IQueryable<T> queryable, 
          string name) where T : IHasName 
{ 
    return queryable.Where(FilterPredicate(name)).SingleOrDefault(); 
} 

Небольшое предостережение: конечно, свойство в интерфейсе ('Name') должно точно соответствовать имени свойства в классах реализации. Предположим, у вас есть класс C с свойством «MyName». Можно было бы попытаться реализовать интерфейс IHasName следующим образом:

public partial class C : IHasName 
{ 
    public string Name {return MyName;} 
} 

Это, конечно, не работает, так как Linq-To-SQL выражения синтаксический анализатор будет использовать «Name» вместо фактической собственности «MyName», так он не сможет сопоставить это выражение с правильным SQL.

+0

«Это, конечно, не сработает, поскольку синтаксический анализатор Linq-To-Sql будет использовать« Имя »вместо фактического свойства« MyName », поэтому он не сможет сопоставить это выражение с правильным SQL». На самом деле, есть способ обойти это - это болезненно, но это работает - http://social.msdn.microsoft.com/Forums/en-US/linqtosql/thread/5691e0ad-ad67-47ea-ae2c- 9432e4e4bd46 –

+0

См. Мое редактирование. Я ищу фильтр для внешнего ключа, не применяя тот же предикат к типам A и B. – Ocelot20

+0

Это очень помогло мне. Меня повесили на попытке использовать интерфейс непосредственно в качестве параметра в предикате. Спасибо. – Ben

Смежные вопросы