Making Criteria Enough

Making Criteria Enough

Old forum URL: forums.lhotka.net/forums/t/3531.aspx


Javawizard posted on Thursday, September 13, 2007

Ok here is the context. Say I have a collection of pets which has 24 exposed, different fetch methods.

Two Examples could be:

static List<Pet> GetPetsLessThanAge(int age) and  static List<Pet> GetPetsEqualToAge(int age)

Because the Fetch method is based takes this criteria it loses the context of what I really want.  When it gets down to the private void DataPortal_Fetch(Criteria criteria) It just has the data in the ‘criteria.Age’ property but did the caller want? ( < age, > age, <= age or potentially something nasty that would include 'ands' and 'ors' like

public static Pet GetMeThatPetWhenIWasSixButNotTheOneThatStunkWorseThanFlipper(Pet.PetType petType, int smellLimit).

I have thought of passing function pointers, or setting up enums, specifying delegates. In your experience, have you determined a clean way of keeping context intact. So when the UI developer calls Pets.GetPetsByABunchOfComplexJunkThatMakesMyLifeDifficult(int a, int b, guid c, string d....) You can know what was really asked for when it gets to the DataPortal_Fetch method?

(Man I hope that was clear)

 

tmg4340 replied on Thursday, September 13, 2007

Given the complexity of your context, and assuming you can't whittle that down some, about the only way I can see out of this is to turn your criteria object into an equivalent of a query object.  You have a couple of options:

1. A mini-object model to... well, model your criteria.  This would include separate objects for AND/OR combinations, potentially built to be nested, and all in an ordered list.  Not necessarily an easy feat, but doable.  If you can simplify the choices, then you may not have to go whole-hog, which means you could maybe get away with a simple comparison object, some enums, and an ordered list.  But if you have to support compound (and possibly nested) expressions, your object model gets tougher.

2. A heavy dose of string-building to take your criteria and essentially turn it into a WHERE clause.  You'll have to do this either way - their filtering options have to be turned into a WHERE clause somewhere.  I'm thinking of something similar to the query builders you see in Access, SQL Server, etc.  The question is whether you want to do that within the confines of the query object, or within the confines of the Pet object.  If you can rather quickly build this kind of UI, then you can probably get this up and running quicker than a query-object solution.

One other possible idea is to foist the complexity upon your user.  It's not necessarily a cop-out - you're really talking about writing a form of a WHERE-clause parser, a not-insignificant feat that may not be worth the time it takes you.  Unless your users are pretty tech-phobic, they can be taught the basics of SQL-style filtering without a ton of work - especially if they're used to working with systems that allow the kind of complex filtering criteria you're talking about.  Then your criteria object simply passes in what they gave you.

Just my two cents...

JoeFallon1 replied on Thursday, September 13, 2007

I removed all the Criteria classes from my BOs and stuck them in a separate file and namespace.

This way I can build a handful of them and re-use them everywhere.

A sample one would be:

<Serializable()> _
Public Class CriteriaCode
 
Inherits Csla.CriteriaBase

 
Public MethodName As String = ""
 
Public Code As String = ""

 
Public Sub New(ByVal BOtype As Type, ByVal methodName As String, ByVal code As String)
   
MyBase.New(BOtype)
   
Me.MethodName = methodName
   
Me.Code = code
 
End Sub

End Class

As you can see, the criteria will pass along a single parameter to the DataPortal (the code value as String). The first parameter is required by CSLA so the framework knows which BO to instantiate. The methodName parameter is used to resolve the issue you are facing.

In the DataPortal you have 2 ways to branch your code. The first is using TypeOf Criteria. If you have 5 Factory methods and use 5 different Criteria classes then this is all you need.

But if you have 5 methods and 3 of them use the exact same Criteria class then you need another way to do the branching. In this case you simply use methodName to tell which factory method passed the criteria.

If methodName = "method1" Then
  'do method1 stuff here

ElseIf methodName = "method2" Then
  'do method2 stuff here

ElseIf methodName = "method3" Then
  'do method3 stuff here

End If

Joe

Copyright (c) Marimer LLC