2016-04-28 3 views
1

У меня есть такие функции, как этот ниже, который загружает таблицу базы данных, используя LinqToSql и возвращает список записей, преобразованных в моей пользовательской модели класса:Нужна помощь упрощение методов с использованием дженериков в C#

public List<AreaModel> LoadListOfAreaModels(Boolean includeDeleted = false) 
    { 
     using (LinqToSqlDataContext dc = new LinqToSqlDataContext()) 
     { 
      IQueryable<Areas> filtered = includeDeleted 
       ? dc.Areas.Where((c) => !c.DataRowDeleted) 
       : dc.Areas; 
      return filtered.Select((c) => AreaModel.ModelFactoryFromLinq(c)).ToList(); 
     } 
    } 

Теперь я имеют довольно много таблиц, и все они должны загружаться и преобразовываться одинаково.

Могу ли я как-то избежать наложения этой функции дюжину раз и просто изменить AreaModel и Areas, например. TownModel и Towns с использованием общей функции?

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

Дополнительная информация: (!, Который не содержит статический фабричный метод, мне нужно позвонить, хотя) Все XxxModel классов имеют общий суперкласс ModelBase, все классы Linq стола (как Areas или Towns) осуществлять общий интерфейс ILinqClass.

Любые идеи о том, как реализовать этот самый элегантный способ?


Вдохновленный knittl «s ответ, я пришел с этим решением:

public List<TModel> LoadListOfModels<TLinq, TModel>(
     Func<TLinq, bool> filter, 
     Func<TLinq, TModel> modelFactory 
     ) 
     where TLinq : class, ILinqClass 
     where TModel : ModelBase 
    { 
     using (LinqToSqlDataContext dc = new LinqToSqlDataContext()) 
     { 
      return dc.GetTable<TLinq>() 
       .Where(filter) 
       .Select(modelFactory) 
       .ToList(); 
     } 
    } 
+0

Является 'DataRowDeleted' определенный в 'ModelBase'? – Lee

+0

@Lee Да, 'DataRowDeleted' это часть интерфейса' ModelBase' реализует –

+0

Проблема, о которой вы говорите, заключается в том, что AreaModel является статическим классом. Почему бы вам не попытаться сделать вас AreaModel, TownModel не статическим классом? Затем они могут реализовать интерфейс, что-то вроде IModelFactory с помощью метода ModelFactoryFromLinq, а затем вы можете передать реализацию этого интерфейса вашему методу LoadList .... –

ответ

2

Вы должны быть в состоянии пройти делегатов/Funcs:

public List<TModel> LoadListOfModels<TDbModel, TModel>(
    Func<LinqToSqlDataContext, TDbModel> modelSelector, 
    Func<TDbModel, bool> isDeleted, 
    Func<TDbModel, TModel> modelFactory, 
    bool includeDeleted = false) 
{ 
    using (LinqToSqlDataContext dc = new LinqToSqlDataContext()) 
    { 
     var models = modelSelector(dc); 
     var filtered = includeDeleted 
      ? models.Where(c => !isDeleted(c)) 
      : models; 

     return filtered.Select(modelFactory).ToList(); 
    } 
} 

Для Area вызова следующим образом:

LoadListOfModels(
    dc => dc.Areas, 
    c => c.DataRowDeleted, 
    Area.ModelFactoryFromLinq, 
    includeDeleted); 

Для Town:

LoadListOfModels(
    dc => dc.Towns, 
    c => c.DataRowDeleted, 
    Town.ModelFactoryFromLinq, 
    includeDeleted); 

Вы могли бы даже быть в состоянии избавиться от параметра includeDeleted. Просто передайте фильтр func Func<TDbModel, bool> filter.

return modelsSelector(dc) 
    .Where(filter) 
    .Select(modelFactory) 
    .ToList(); 

Вызов:

LoadListOfModels(dc => dc.Areas, c => true, Area.ModelFactoryFromLinq); 
LoadListOfModels(dc => dc.Areas, c => !c.DataRowDeleted, Area.ModelFactoryFromLinq); 
+0

Спасибо, мне тоже удалось избавиться от параметра modelSelector, см. Мой отредактированный вопрос для моего окончательного подхода. –

1

Попробуйте этот подход:

public abstract class BaseClass<TModel> where TModel : class 
{ 
    public bool DataRowDeleted { get; set; } 
    public abstract TModel ModelFactoryFromLinq(); 
} 

public class Area : BaseClass<AreaModel> 
{ 
    public override AreaModel ModelFactoryFromLinq() 
    { 
     return new AreaModel(); 
    } 
} 

public static List<TModel> LoadListOfAreaModels<TContext, TModel>(bool includeDeleted = false) 
    where TContext : BaseClass<TModel>, new() 
    where TModel : class 
{ 
    using (var dc = new LinqToSqlDataContext()) 
    { 
     IQueryable<TContext> filtered = includeDeleted 
      ? dc.GetTable<TContext>().Where((c) => !c.DataRowDeleted) 
      : dc.GetTable<TContext>(); 
     return filtered.Select((c) => c.ModelFactoryFromLinq()).ToList(); 
    } 
} 

РЕАЛИЗАЦИЯ:

List<AreaModel> result = SomeClassName.LoadListOfAreaModels<Area, AreaModel>(); 
0

Если DataRowDeleted определен в ModelBase вы должны быть в состоянии сделать:

public static IQueryable<TModel> LoadListOfQuery<T, TModel>(IQueryable<T> source, Expression<Func<T, TModel>> selector, bool includeDeleted = false) where T : ModelBase { 
    IQueryable<T> filtered = includeDeleted ? source : source.Where(s => !s.DataRowDeleted); 
    return filtered.Select(selector); 
} 

Затем добавить функцию для оценки запроса данного контекста:

public static List<T> ExecList(Func<LinqToSqlDataContext, IQueryable<T>> qf) 
{ 
    using(var c = new LinqToSqlDataContext()) 
    { 
     var q = qf(c); 
     return q.ToList(); 
    } 
} 

Тогда вы можете сделать:

public List<AreaModel> LoadListOfAreaModels(bool includeDeleted = false) 
{ 
    ExecList(c => LoadListOfQuery(c.Areas, a => AreaModel.ModelFactoryFromLinq(a), includeDeleted); 
} 
Смежные вопросы