I have some questions about Complex Criteria’s object

I have some questions about Complex Criteria’s object

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


BeyondNet posted on Saturday, January 18, 2014

I have a interface (client) with multiples filters, per e.j: 

 

- Search by Code

- Search by Name

- Search by Last Name

- Search by ....

 

In these cases, I look with always the need of create a new Criteria object, per e.j.:

 

- SearchByCodeCriteria

- SearchByNameCriteria

- SearchByLastNameCriteria

- SearchBy....

 

A form of solution maybe create a class with this filters:

 

public class Filters

{

      string Code

      string Name

      string LastName

}

 

This class  may put in the constructor of any Criteria Object. But the problem is the same, I need always of conditionals, p.e.:

 

If (!String.NullOrEmpty(Foo.Code))

   Filters.Code = Foo.Code;

 

This same problem repeat been in the moment to fetch in the DataPortal:

 

If (!String.NullOrEmpty(Filters.Code))

   data = targetRepository.FetchByCode(Filters.Code);

 

If (!String.NullOrEmpty(Filters.Name))

   data = targetRepository.FetchByName(Filters.Name);

 

 

The questions is:

 

Exists any pattern for Criterias, similar to Specifications in DDD, I understand with CSLA .NET is not a ORM, but I think the conditionals in CSLA framework to Criterias Objects is a little problem.

 

Can you help me with any pattern?

 

P.D.: I use IoC and DI with Unity, also use Managed Extensibility Framework (MEF) with CSLA .NET to apply polymorphism, but my problem is when I need apply this concepts with the Criteria Objects.

 

Maybe an option:

 

public interface IDynamicList<T>

    {

        List<T> FindAllByCriteria(string criteria);

        List<T> FindAllByCriteria(Func<T, bool> criteria);

    }

 

 [Export(typeof(ICustomerRepository))]

    public class CustomerMock : ICustomerRepository

    {

        public List<Dto.CustomerDto> FindAllByCriteria(Func<Dto.CustomerDto, bool> criteria)

        {

            throw new NotImplementedException();

        }

    }

 

Best regards

JonnyBee replied on Monday, January 20, 2014

My preference is to have one or more criteria objects with multiple fields (when required).

This makes the data contract a lot easier and you only need to add extra logic in the DataPortal_XYZ / ObjectFactory methods.

BeyondNet replied on Monday, January 20, 2014

Johnny, thanks for your help.

Is true, really we are using one criteria of search per every need of search. But I think if we use some pattern as "Chains of Responsability", "Strategy" or "Dependency Injection", we can achieve some solution.

This article is interesting, in it we can view the use of an architecture based in NHibernate, but I think can be used as a sample base:

URL: http://weblogs.asp.net/thangchung/archive/2010/06/20/breaking-if-statements-with-pattern.aspx

Best Regards

en → es
archivo
sustantivo: archivo

JonnyBee replied on Monday, January 20, 2014

No, don't get me wrong.

When I have a "search form" I will typically have a separate Business Object (with additional business rules) and use this object as criteria on the fetch.

If I have multiple "search forms" there will probably also be separate criteria objects.

 

BeyondNet replied on Monday, January 20, 2014

For the moment, I'm applying this solution: Basically is similar to "Chain of Responsability" pattern, but I use Dependency Injection, because I think is a best solution.  The next is optimizing the code with Func<> or Predicated and Generics.

DI:

    public interface INodeDataFilter

    {

        NodeDataInfoList List(NodeDataSearchFilters filters);

    }

   public class NodeDataFilterCode : INodeDataFilter

    {

        public NodeDataInfoList List(NodeDataSearchFilters filters)

        {

            NodeDataSearchCriteria criteria = new NodeDataSearchCriteria(filters);

            return NodeDataInfoList.GetAllNodeData(criteria);

        }

    }

 

    public class NodeDataFilterName : INodeDataFilter

    {

        public NodeDataInfoList List(NodeDataSearchFilters filters)

        {

            NodeDataSearchCriteria criteria = new NodeDataSearchCriteria(filters);

            return NodeDataInfoList.GetAllNodeData(criteria);

        }

    }

Controller:

 

      public ActionResult ManagerGridPartial(string criteriaType, string filterValue, string nodeDataCode, string nodeDataName, string nodeId, int status)

        {

            var container = UnityConfig.GetConfiguredContainer();

            NodeDataSearchFilters filters = new NodeDataSearchFilters()

            {

                NodeDataCode = criteriaType == "0" ? filterValue : string.Empty,

                NodeDataName = criteriaType == "1" ? filterValue : string.Empty,

                NodeId = nodeId,

                Status = status,

            };           

            var concret = container.Resolve<INodeDataFilter>(criteriaType);

            NodeDataInfoList result = concret.List(filters);

            return this.PartialView(SiteMapViewUrl.NodeData_ManagerResultPartial, result);

        }

 

InfoList - BO:

    private void DataPortal_Fetch(NodeDataSearchCriteria criteria)

        {

            var rlce = RaiseListChangedEvents;

            RaiseListChangedEvents = false;

            IsReadOnly = false;

 

            List<NodeDataDto> data = null;

 

           //Here, always conditionals problems

            if (!string.IsNullOrEmpty(criteria.NodeDataCode))

                data = TargetRepository.FetchCustomAll(p => p.Code == criteria.NodeDataCode);

 

            if (!string.IsNullOrEmpty(criteria.NodeDataName))

                data = TargetRepository.FetchCustomAll(p => p.Name == criteria.NodeDataName);

 

            foreach (var item in data)

            {

                Add(NodeDataInfo.GetNodeData(item));

            }

 

            IsReadOnly = true;

            RaiseListChangedEvents = rlce;

        }

 

Mock:

 

    public List<NodeDataDto> FetchCustomAll(Func<NodeDataDto, bool> criteria)

        {

            var data = NDatabaseManager.Instance.Database.QueryAndExecute<NodeDataDto>().Where(criteria).ToList();

 

            if (data == null)

            {

                throw new DataAccessNotFoundException("NodeDataTable is not exists");

            }

 

            List<NodeDataDto> result = new List<NodeDataDto>();

            Mapper.Map(data, result);

 

            return result;

        }

 

Best Regards

Copyright (c) Marimer LLC