Using One Criteria Class for differents searchs criterias in Object Lists (BussinessListBase, ReadOnlyListBase)

Using One Criteria Class for differents searchs criterias in Object Lists (BussinessListBase, ReadOnlyListBase)

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


foxhard posted on Friday, January 29, 2010

Hi,

I have a class ContactList : BusinessListBase<ContactList, ContactChild>.

I need get Contacts
- by State
- by Category
- by Country,
- by City,
- by State and Category
- by State and Category and Country and City

The If I use the Criteria class..then I will need 6 Criteria Classes...one for each search criteria.

Then I think I need only one Criteria class with all search criterias that you needs...

This is a example:


enum SearchType
{
     ByState,
     ByCategory,
     ByCountry,
     ByCity,
     ByStateCategory,
     ByStateCategoryCountryCity,
}

[Serializable]
internal class SpecialFilterCriteria: CriteriaBase
{
     Public int ContactId {Get; Set;}
     Public int StateId {Get; Set;}
     Public int CategoryId {Get; Set;}
     Public int CountryId {Get; Set;}
     Public int CityId {Get; Set;}
    
     Public SearchType Kind {Get; Set;}
   
     Public SpecialFilterCriteria(){}
}

Then In Factory Methods region:

public static ContactList GetContactsByStateId(int stateId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByState,
                        StateId=stateId});
}
public static ContactList GetContactsByCategoryId(int categoryId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByCategory,
                        CategoryId=stateId});
}
public static ContactList GetContactsByCountryId(int countryId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByCountry,
                        Countryd=countryId});
}
public static ContactList GetContactsByCityId(int cityId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByCity,
                        CityId=cityId});
}
public static ContactList GetContactsByStateIdCategoryId(int stateId, int categoryId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByStateCategory,
                        StateId=stateId,
                        CategoryId=categoryId});
}
public static ContactList GetContactsByStateIdCategoryIdCountryIdCityId(int stateId,
                                     int categoryId,
                                    int countryId,
                                    cityId)
{
    return DataPortal.Fetch<ContactList>(new SpecialCriteria(){
                        Kind=ByStateCategoryCountryCity,
                        StateId=stateId,
                        CategoryId=categoryId,
                        Countryd=countryId,
                        CityId=cityId});
}


Then in the DataAccess region, you have only one DataPortal_Fetch() using switch for differents types of searches.

private void DataPortal_Fetch(SpecialFilterCriteria criteria)
{
     //....code...
    switch(criteria.Kind)
   {
        case
ByState:
              //Code to get data from database with specific filter.
              break;
        case ByCategory:
              //Code to get data from database with specific filter.
              break;
        case ByCountry:
              //Code to get data from database with specific filter.
              break;
        case ByCity:
              //Code to get data from database with specific filter.
              break;
       ByStateCategory:
              //Code to get data from database with specific filter.
              break;
       ByStateCategoryCountryCity:
              //Code to get data from database with specific filter.
              break;
   }
    //....more code...
}


What do you thing about that?....is it good, bad, more or less, not recommended???...why???

Thanks,
Cristhiam





ballistic replied on Friday, January 29, 2010

Personally, I would create the 6 different criteria classes and only have the fields each one needed.  It's really not that much more code.

Having said that, I like the solution you came up with.  I have come across similar situations where I needed to pull from the same data source, just vary the criteria.  Had I come up with your solution, I would have used it :)

 - Andy

ajj3085 replied on Friday, January 29, 2010

Don't think there's anything wrong with your approach, and I've done similar things in the past.  If you have rules (like if you specify the Kind is State, and you want to require state) you should create a BB subclass which acts as the criteria.

xAvailx replied on Friday, January 29, 2010

Why don't you make the criteria public and just have one factory method that takes in the criteria with the settings from the consumer?

foxhard replied on Friday, January 29, 2010

I have thought about doing something like this:

Now I have added a new Criteria Class...look at the code:

public enum SearchType
{
     ByState,
     ByCategory,
     ByCountry,
     ByCity,
     ByStateCategory,
     ByStateCategoryCountryCity,
}

[Serializable]
public class SpecialFilterCriteria: CriteriaBase
{
     Public int ContactId {Get; Set;}
     Public int StateId {Get; Set;}
     Public int CategoryId {Get; Set;}
     Public int CountryId {Get; Set;}
     Public int CityId {Get; Set;}

     Public SpecialFilterCriteria(){}
}

[Serializable]
private class MainCriteria: CriteriaBase
{
     Public SpecialCriteria Criteria
{Get; private Set;}
     Public SearchType Kind {Get; private Set;}

     Public SpecialFilterCriteria(SpecialCriteria criteria, SearchType kind)
     {
           this.Criteria = criteria;
           this.Kind = kind;   
     }
}

Then In Factory Methods region:

public static ContactList GetContacts(SpecialFilterCriteria criteria, SearchType searchType)
{
    return DataPortal.Fetch<ContactList>(new MainCriteria(criteria, searchType));
}

Then in the DataAccess region, you have only one DataPortal_Fetch() using switch for differents types of searches.

private void DataPortal_Fetch(MainCriteria mainCriteria)
{
     //....code...
    switch(mainCriteria.Kind)
   {
        case
ByState:
              //Code to get data from database with specific filter.
              break;
        case ByCategory:
              //Code to get data from database with specific filter.
              break;
        case ByCountry:
              //Code to get data from database with specific filter.
              break;
        case ByCity:
              //Code to get data from database with specific filter.
              break;
       ByStateCategory:
              //Code to get data from database with specific filter.
              break;
       ByStateCategoryCountryCity:
              //Code to get data from database with specific filter.
              break;
   }
    //....more code...
}


What do you think about that?

ajj3085 replied on Monday, February 01, 2010

I'd get rid of the private criteria class, and move the kind property to the public one.  I'd also probably change it to inherit BusinessBase, so I can attach rules which take Kind into account (so if you choose state it requires a value for state).

But that's me and I don't think you're off base at all.

xAvailx replied on Monday, February 01, 2010

I think here we get to personal preference...for example I would probably only have one criteria, I don't see the benefit of passing in two criteria classes, but then again I don't know your requirements.

am_fusion replied on Tuesday, February 02, 2010

As was previously stated by others, I think your approach is fine.  I, however, do not like the switch code.  It is a little 'smelly'  considering that every new filter will grow the switch statement.  Eventually you may end up with a DataPortal_Fetch where you won't be able to see the begining from the end (a sign that the method has gotten too large).  Also, this design may lead to duplicate code within each of the case segments.  

Copyright (c) Marimer LLC