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
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.
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
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.
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