Reputation: 6736
I have functions like this one below that loads a database table using LinqToSql and returns a list of the entries converted into my custom model class:
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();
}
}
Now I have quite a few tables and all have to get loaded and converted in the same way.
Can I somehow avoid typing this function a dozen times and just changing the AreaModel
and Areas
to e.g. TownModel
and Towns
by using a generic function?
I already tried this, but failed because I could not find a way to call a static class method if I only have the generic type parameter of it.
Further info: All XxxModel
classes have the common superclass ModelBase
(which does not contain the static factory method I need to call though!), all Linq table classes (like Areas
or Towns
) implement the common interface ILinqClass
.
Any ideas on how to implement this the most elegant way?
Inspired by knittl's answer, I came up with this solution:
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();
}
}
Upvotes: 1
Views: 109
Reputation: 13488
Try this approach:
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();
}
}
IMPLEMENTATION:
List<AreaModel> result = SomeClassName.LoadListOfAreaModels<Area, AreaModel>();
Upvotes: 1
Reputation: 265211
You should be able to pass delegates/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();
}
}
For Area
call as follows:
LoadListOfModels(
dc => dc.Areas,
c => c.DataRowDeleted,
Area.ModelFactoryFromLinq,
includeDeleted);
For Town
:
LoadListOfModels(
dc => dc.Towns,
c => c.DataRowDeleted,
Town.ModelFactoryFromLinq,
includeDeleted);
You might even be able to get rid of the includeDeleted
parameter. Simply pass a filter func Func<TDbModel, bool> filter
.
return modelsSelector(dc)
.Where(filter)
.Select(modelFactory)
.ToList();
Call:
LoadListOfModels(dc => dc.Areas, c => true, Area.ModelFactoryFromLinq);
LoadListOfModels(dc => dc.Areas, c => !c.DataRowDeleted, Area.ModelFactoryFromLinq);
Upvotes: 2
Reputation: 144136
If DataRowDeleted
is defined in ModelBase
you should be able to do:
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);
}
Then add a function to evaluate a query given a context:
public static List<T> ExecList(Func<LinqToSqlDataContext, IQueryable<T>> qf)
{
using(var c = new LinqToSqlDataContext())
{
var q = qf(c);
return q.ToList();
}
}
Then you can do:
public List<AreaModel> LoadListOfAreaModels(bool includeDeleted = false)
{
ExecList(c => LoadListOfQuery(c.Areas, a => AreaModel.ModelFactoryFromLinq(a), includeDeleted);
}
Upvotes: 0