5

Assuming a basic 3-Tier application (UI-Service-Data Access) with a total abstraction of Data Access layer (SQL, Xml ...)

The UI applications are composed with Datagrids with multi criteria filters, find etc..

So how-to deal with mutli-criteria queries in this architecture without having to create multiple service methods with all possible criteria as parameters...

Note that UI tier doesn't know how the DAL works.

Yoann. B
  • 11,075
  • 19
  • 69
  • 111

7 Answers7

1

That is what a DTO is for.

blu
  • 12,905
  • 20
  • 70
  • 106
0

I use subsonic and pass a collection of where clauses to the service method

ptutt
  • 1,338
  • 3
  • 18
  • 35
  • How do you handle this ? you pass SQL where clauses to the service method ? My UI tier doesn't know how the DAL works, so i can't pass plain SQL where clauses through my service methods. – Yoann. B Oct 30 '09 at 20:55
  • You have share the DAL with the client to get this to work. It's not really 'pure' but works really well. You just gotta know that you can't call the CRUD methods from the client. – ptutt Oct 30 '09 at 21:05
  • @ptutt No i can't share the DAL with the client. I think it's not a great architecture design. The client only talk to service layer (business) – Yoann. B Oct 30 '09 at 21:11
  • You could split the table definition classes (ie dto's) and where clause classes from the DAL into a separate assembly that could be shared between client and server. – ptutt Oct 30 '09 at 21:26
  • @Yoann: i think what ptutt means is that you need to share the model objects (DTOs) with the client. these may or may not be in your DAL project and are certainly not your data access implementation (which i think is this 'not a great architecture design' you're reffering to) so you're ok there. – Matt Kocaj Nov 08 '09 at 06:30
0

I'm not sure if this is what you're looking for, but I use the DAL as a factory to create a DAL-aware object, with reasonable public properties and/or methods that encapsulate the various filter criteria.

Ask the DAL to create the object, edit filter criteria as needed, give it back, and let the DAL do it's thing with the object in whatever way it needs to for its given access method.

This, of course, assumes that you don't have a completely open-ended data structure...that you have a known and reasonable sized set of possible filter criteria. If it needs to be flexible to the point where you can pass in arbitary filter criteria for unknown data structures, this probably isn't your solution.

Beska
  • 12,445
  • 14
  • 77
  • 112
  • @Beska I need a generic and abstract way to handle multi criteria queries. But not specifics methods like this : public IList FindSomething(int filter1, string filter2 ...) But maybe a more flexible way with LINQ Expression like : public IList Find(Expression filters[]) I dunno ... – Yoann. B Oct 30 '09 at 21:09
0

You could create an object that holds something like a KeyValuePair for each criteria you want to filter on. Your DAL can then build the where condition from that..

Like this:

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

You could quite easily extend on that, e.g. add an "operator" field to the FilterCriteria class, to allow for more filtering options than just exact matches..

andyp
  • 6,229
  • 3
  • 38
  • 55
0

I like to use Query-By-Example for this. This is where you can pass in an actual example DTO and any non-default-valued fields represent criteria for query.

e.g.

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

var customers = svc.GetCustomersLike(example);

This could be used from the service layer, or from a higher layer too.

0

Check out Rob's Storefront tutorial. It uses a model that is passed up from the DAL, thru the Service layer and even used in the UI layer. This ok, and doesn't break you requirement where the UI can't know how the DAL is implemented. You can easily move your Domain Model onto another VS project in the event you wanted 3rd party apps to access your service layer and not be aware how the DAL works.

This answer has some details about ways to abstract functions of LinqToSql away in higher layers. You might want to do this if, like me, you love the deferred execution features of LinqToSql but you don't want your app to depend on LinqToSql as a data provider.

Community
  • 1
  • 1
Matt Kocaj
  • 11,278
  • 6
  • 51
  • 79
0

There are multiple ways to do it, I used mix of criteria API and query objects. For example if you have Persons collection which you want to query:

1) The more flexible way criteria 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) Strongly described query object:

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

Use Nullable<> for Value types and assign Null to indicate that parameter is not required.

Each method has positive and negative sides.

Alex Burtsev
  • 12,418
  • 8
  • 60
  • 87