我正在构建的应用程序中有几个区域,看起来我可能不得不违反DRY(不要重复自己)原则中的生活日光。我真的很想保持干爽而不会被人嘲笑,并且想知道是否有人可以给我一个雨披。作为背景,我使用的是C#/ .NET 3.51 SP1,Sql Server 2008和Linq-to-Sql。
基本上,我的情况围绕以下情况展开。我需要能够从我的数据库中的几乎任何表中检索过滤的项目列表,或者我需要能够从给定主键ID的数据库中的任何表中检索单个项目。我很确定这些问题的最佳解决方案将涉及大量的仿制药和/或反射。
以下是更深入的两个挑战。 (请原谅详细程度。)
对于每个查找表,我有时需要返回所有记录的列表。其他时候我只需要返回活动记录。任何Linq-to-Sql数据上下文自动包含每个TableName的List属性。不幸的是,我不相信我可以使用它的原始形式,因为它是未经过滤的,我需要在IsActive属性上应用过滤器。
一种选择是为所有50个表编写类似于以下的代码。育!!!
public List<AAA> GetListAAA(bool activeOnly)
{
return AAAs.Where(b => b.IsActive == true || b.IsActive == activeOnly).OrderBy(c => c.Title).ToList();
}
这不会非常困难,但它确实增加了维护的负担。
注意:在返回列表时,保持基础数据类型非常重要。可以修改这些查找表中的记录,我必须适当地应用更新。
我不确定这里最好的方法是什么。我想到的一些可能性包括以下内容。 (我对其实施没有具体的想法。我只是将它们列为思考的食物。)
一个。在数据上下文中有一个类似GetTableNameItemByID(Guid id)的方法。 (好) B.在数据上下文中有一个像GetItem(this,string tableName,Guid id)这样的扩展方法。 (更好) C.有一个像GetItem这样的通用方法或扩展方法(this,Table,Guid id)。 (我甚至不知道这是否可能,但它是最干净的。)(最佳)
附加说明
由于各种原因,我已经为我的数据上下文创建了一个部分类。如果方法作为普通方法或扩展方法的单独静态类包含在该部分类中,那肯定是可以接受的。
答案 0 :(得分:6)
由于您已经部分实施了数据上下文,因此可以添加:
public IQueryable<T> GetList<T>( bool activeOnly ) where T : class, IReferenceData
{
return this.GetTable<T>()
.Where( b => !activeOnly || b.isActive )
.OrderBy( c => c.Title );
}
保留数据的IQueryable字符将推迟执行查询,直到您准备好实现它为止。请注意,您可能希望省略默认顺序,或者使用单独的方法,无论是否订购,都可以根据需要应用不同的顺序。如果将它保留为IQueryable,这可能更有价值,因为如果您愿意,可以将它与分页一起使用以减少实际返回的数据量(每个查询)。
答案 1 :(得分:3)
有一种设计模式可以满足您的需求,称为“通用存储库”。使用此模式,您将获得IQueryable,而不是实体的实体列表,这样您就可以随时使用查询执行其他操作。点是让业务层在通用方法中随时获得所需的任何内容。
您可以找到示例here。
答案 2 :(得分:2)
您是否考虑过使用代码生成工具?看看CodeSmith。使用这样的工具或T4将允许您自动生成过滤器功能,并使它们易于维护。
我不确定提供T4的最佳链接,但您可以从this video开始。
答案 3 :(得分:2)
这会满足您的需求吗?
public static IEnumerable<T> GetList<T>(this IEnumerable<IReferenceData> items, bool activeOnly)
{
return items.Where(b => b.IsActive == true || b.IsActive == activeOnly).OrderBy(c => c.Title).Cast<T>().ToList();
}
您可以像这样使用它:
IEnumerable<IReferenceData> yourList;
List<DerivedClass> filtered = yourList.GetList<DerivedClass>(true);
答案 4 :(得分:1)
要做这样的事情而不需要接口等,你可以使用动态Expression
;类似的东西:
public static IList<T> GetList<T>(
this DataContext context, bool activeOnly )
where T : class
{
IQueryable<T> query = context.GetTable<T>();
var param = Expression.Parameter(typeof(T), "row");
if(activeOnly)
{
var predicate = Expression.Lambda<Func<T, bool>>(
Expression.Equal(
Expression.PropertyOrField(param, "IsActive"),
Expression.Constant(true,typeof(bool))
), param);
query = query.Where(predicate);
}
var selector = Expression.Lambda<Func<T, string>>(
Expression.PropertyOrField(param, "Title"), param);
return query.OrderBy(selector).ToList();
}