如何处理3层架构中的多条件查询

5
假设有一个基本的三层应用程序(UI-Service-Data Access),其中数据访问层(SQL、Xml等)完全抽象化。
UI应用程序由带有多个条件过滤器、查找等功能的数据网格组成。
那么,在不必创建具有所有可能参数的多个服务方法的情况下,如何处理这种体系结构中的多条件查询...
请注意,UI层不知道DAL的工作原理。

我有一个类似的问题。 - Tom Neyland
这里有一个开始,但是太“SQL依赖”了... http://www.drewnoakes.com/code/util/Filter.html - Yoann. B
7个回答

1

这就是DTO的作用。


0
你可以创建一个对象,为您想要过滤的每个条件保存一个类似于KeyValuePair的东西。然后您的数据访问层(DAL)就可以根据这个条件构建where条件语句。
就像这样:
class MultiCriteriaFiltering
{
    List<FilterCriteria> Criterias;

    // this method just sits here for simplicity - it should be in your DAL, not the DTO
    string BuildWhereCondition()
    {
        StringBuilder condition = new StringBuilder();
        condition.Append("WHERE (1=1) "
        foreach (FilterCriteria criteria in Criterias)
        {
            condition.Append(" AND ").Append(criteria.FieldName).Append(" = ");
            condition.Append("'").Append(criteria.FilterValue).Append("'");
        }
        return condition.ToString();
    }
}

class FilterCriteria
{
    string FieldName { get; set; }
    object FilterValue  { get; set; }
}

你可以很容易地扩展它,例如向FilterCriteria类添加一个"operator"字段,以允许更多的过滤选项而不仅仅是精确匹配。

0

有多种方法可以做到这一点,我使用了标准 API 和查询对象的混合。

例如,如果您想查询 Persons 集合:

1)更灵活的方式是使用标准 API:GetPerson(IList query)

public class Criteria
{
 Object Property; // (Domain property, not DB)// (String Or Lambda) Age, Father.Age, Friends, etc
 Object Operator; //(Enum or String)(Eq, Gr, Between,Contains, StartWith, Whatever...)
 Object Value; // (most likely Object, or use generics Criteria<T>), (Guid, int[], Person, any type).
}

2) 强类型化的查询对象:

public class PersonQuery
{
 Guid? Id;
 GenderEnum? Gender;
 Int32? Age;
 Int32? AgeMin;
 Int32? AgeMax;
 String Name;
 String NameContains;
 Person FatherIs;
 Person MotherIs;
 //...
}

对于值类型,请使用Nullable<>并分配Null来指示参数不是必需的。

每种方法都有积极和消极的方面。


0

我使用Subsonic,并将一组where子句传递给服务方法


你如何处理这个问题?你将 SQL where 子句传递给服务方法吗?我的 UI 层不知道 DAL 的工作原理,因此我不能通过服务方法传递纯 SQL where 子句。 - Yoann. B
你需要与客户共享DAL才能使其正常工作。它不是真正的“纯粹”,但非常有效。你只需要知道不能从客户端调用CRUD方法。 - ptutt
我不能与客户共享数据访问层(DAL)。我认为这不是一个很好的架构设计。客户只能与服务层(业务逻辑层)交互。 - Yoann. B
你可以将表定义类(即DTO)和DAL中的where子句类拆分到一个单独的程序集中,以便客户端和服务器之间共享。 - ptutt
@Yoann:我认为ptutt的意思是你需要与客户端共享模型对象(DTO)。这些对象可能在你的DAL项目中,也可能不在其中,但肯定不是你的数据访问实现(我想这就是你所指的“不太好的架构设计”),所以你没问题。 - Matt Kocaj

0

我不确定这是否是您要寻找的内容,但我使用DAL作为工厂来创建一个具有合理公共属性和/或方法的DAL感知对象,以封装各种过滤条件。

请求DAL创建对象,根据需要编辑过滤条件,将其返回,并让DAL以其给定的访问方法对对象进行必要的操作。

当然,这假设您没有完全开放的数据结构...您拥有已知且合理大小的可能过滤条件集。如果它需要灵活到可以传递未知数据结构的任意过滤条件的程度,那么这可能不是您的解决方案。


@Beska 我需要一种通用和抽象的方法来处理多条件查询。但不是像这样的具体方法:public IList<MyObject> FindSomething(int filter1, string filter2 ...)而是可能更灵活的方式,使用LINQ表达式,例如:public IList<T> Find(Expression filters[])我不知道... - Yoann. B

0

我喜欢使用 Query-By-Example 来实现这个功能。这是一种可以传递实际示例 DTO 的方法,任何非默认值字段都代表查询条件。

例如:

CustomerDTO example = new CustomerDTO();
example.lastName = "jones";
AddressDTO exAddr = new AddressDTO();
exAddr.city = "Boston";
example.addresses.add(exAddr);

var customers = svc.GetCustomersLike(example);

这可以从服务层或更高层使用。


0

看看Rob的Storefront教程。它使用了一个模型,从DAL传递到服务层,甚至在UI层中使用。这是可以的,并且不会违反您的要求,即UI不能知道如何实现DAL。如果您希望第三方应用程序访问您的服务层而不知道DAL的工作方式,您可以轻松地将域模型移动到另一个VS项目中。

这个答案有一些关于如何在更高层次上抽象LinqToSql函数的细节。如果像我一样,您喜欢LinqToSql的延迟执行功能,但又不想让您的应用程序依赖于LinqToSql作为数据提供程序,那么您可能需要这样做。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接