繁体   English   中英

C#泛型问题

[英]C# Generics Question

在我正在构建的应用程序中,我有几个方面看起来像我可能不得不违反DRY(不要自己重复)原则而违反生活日光。 我真的很想保持干燥,不要被软管缠住,想知道是否有人可以给我披风。 对于背景,我使用的是C#/。NET 3.51 SP1,Sql Server 2008和Linq-to-Sql。

基本上,我的情况与以下情况有关。 我需要能够从数据库中的几乎任何表中检索项目的过滤列表,或者需要给定主键ID的情况下,能够从数据库中的任何表中检索单个项目。 我非常确定,针对这些问题的最佳解决方案将涉及大量的泛型和/或反射。

以下是两个挑战。 (请原谅。)

  1. 给定一个表名(或者可能是一个复数的表名),我希望能够检索表中元素的过滤列表。 具体来说,此功能将与查找表一起使用。 (此数据库中大约有50个查找表。经常会添加和/或删除其他表。)当前的查找表都实现了一个称为IReferenceData的接口(我的),并且具有ID(PK),Title,Description和ID字段。活跃。

对于每个查找表,有时我需要返回所有记录的列表。 有时我只需要返回活动记录。 任何Linq-to-Sql数据上下文都会为每个TableName自动包含一个List属性。 不幸的是,我不相信我可以使用它的原始形式,因为它未经过滤,我需要在IsActive属性上应用过滤器。

一种选择是为所有50个表编写类似于以下代码的代码。 k!

public List<AAA> GetListAAA(bool activeOnly)
{
    return AAAs.Where(b => b.IsActive == true || b.IsActive == activeOnly).OrderBy(c => c.Title).ToList();
}

这并不是很难,但是确实增加了维护负担。

注意:重要的是,返回列表时,我必须维护基础数据类型。 这些查询表中的记录可能会被修改,我必须适当地应用更新。

  1. 对于我的150个表中的每个表,我需要能够通过其主键ID检索单个记录(FirstOrDefault或SingleOrDefault)。 同样,我不希望多次编写相同的代码。 我希望有一种可以用于所有表的方法。

我不太确定最好的方法是什么。 我想到的一些可能性包括以下几种。 (我没有具体的想法来实现它们。我只是将它们列为可思考的食物。)

A.在数据上下文上有一个类似GetTableNameItemByID(Guid id)的方法。 (很好)B.在数据上下文上有一个像GetItem(this,string tableName,Guid id)这样的扩展方法。 (更好)C.拥有通用方法或扩展方法,例如GetItem(this,Table,Guid id)。 (我什至不知道这是否可行,但是使用起来最干净。)(最佳)

补充笔记

由于各种原因,我已经为我的数据上下文创建了一个部分类。 如果方法作为普通方法或作为扩展方法的单独静态类包含在该部分类中,那肯定是可以接受的。

由于您已经部分实现了数据上下文,因此可以添加:

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,则可能会更有价值,因为可以将其与分页一起使用,以减少实际返回的数据量(每个查询)(如果需要)。

有一个满足您需求的设计模式称为“通用存储库”。使用此模式,您将获得一个IQueryable而不是实体的真实列表,这使您可以在进行查询时做其他事情。关键是让业务层可以使用通用方法随时获得所需的一切。

您可以在此处找到示例。

您是否考虑过使用代码生成工具? 看看CodeSmith 使用类似T4的工具将使您能够自动生成过滤器功能,并使它们易于维护。

我不确定提供T4的最佳链接,但是您可以从此视频开始。

这会满足您的需求吗?

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);

要在不要求接口等的情况下执行此类操作,可以使用动态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();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM