views:

883

answers:

2

I'm trying to retrieve a list of orders based on parameters specified by a user (basic search functionality). The user will enter either an orderId or a bunch of other params, those will get wrapped up into a message, and eventually make their way to the method below. My question is, how do I only look at the parameters that actually have values? So if a user were to enter a received date range and a store number and all other fields were null, I want to return orders for stores received in the date range and ignore all the null parameters. At first I was thinking I could use a conjunction, but I can't see a way to ignore the null parameters. Then I started splitting things out into the if statements below the main expression, but I don't want to look at those criteria if the user provides an externalId. Is there a simple way to do this?

        public IList<Core.Order> GetOrderByCriteria
        (
        string ExternalId,
        int? Store,
        int? Status,
        DateTime? beforeTransmissionDate, DateTime? afterTransmissionDate,
        DateTime? beforeAllocationProcessDate, DateTime? afterAllocationProcessDate,
        DateTime? beforeReceivedDate, DateTime? afterReceivedDate
        )
    {
        try
        {
            NHibernate.ICriteria criteria = NHibernateSession.CreateCriteria(typeof(Core.Order))
                .Add(Expression.Or
                        (
                        Expression.Like("ExternalId", ExternalId),
                        Expression.Conjunction()
                            .Add(Expression.Between("ReceivedDate", beforeReceivedDate, afterReceivedDate))
                            .Add(Expression.Between("TransmissionDate", beforeTransmissionDate, afterTransmissionDate))
                            .Add(Expression.Between("AllocationProcessDate", beforeAllocationProcessDate, afterAllocationProcessDate))
                        )
                     );

            if(Store.HasValue)
                criteria.Add(Expression.Eq("Status", Status));

            if(Status.HasValue)
                criteria.Add(Expression.Eq("Store", Store));


            return criteria.List<Core.Order>();
        }
        catch (NHibernate.HibernateException he)
        {
            DataAccessException dae = new DataAccessException("NHibernate Exception", he);
            throw dae;
        }
    }
A: 

I had to do something similar not long ago. I'm pretty sure you can modify this to fit your needs.

    private ICriteria AddSearchCriteria(ICriteria criteria, string fieldName, string value)
    {

        if (string.IsNullOrEmpty(fieldName))
            return criteria;

        if(string.IsNullOrEmpty(value))
            return criteria;

        criteria.Add(Expression.Like(fieldName, "%" + value + "%"));

        return criteria;
    }

The code calling the method ended up looking like this:

var query = session.CreateCriteria(typeof (User));

AddSearchCriteria(query, "FirstName", form["FirstName"]);
AddSearchCriteria(query, "LastName", form["LastName"]);

var resultList = new List<User>();
query.List(resultList);
return resultList;

Leave it up to the function to determine if the input is valid and whether to return the unmodified ICriteria or to add another Expression before returning it.

JustinT
Only thing I didn't like here is a good deal of my criteria are not strings and I didn't want to have to convert all params.
Justin Holbrook
+1  A: 

I wound up dropping the whole conjunction thing and replacing the code in the try block with the code below. I also used joins which reduced the number of db accesses and reduced the amount of code needed.

NHibernate.ICriteria criteria = NHibernateSession.CreateCriteria(typeof(Core.Order));

            if (!String.IsNullOrEmpty(ExternalId))
            {
                criteria.Add(Expression.Like("ExternalId", ExternalId));
            }

            if (beforeReceivedDate != null && afterReceivedDate != null)
                criteria.Add(Expression.Between("ReceivedDate", beforeReceivedDate, afterReceivedDate));

            if (beforeTransmissionDate != null && afterTransmissionDate != null)
                criteria.Add(Expression.Between("TransmissionDate", beforeTransmissionDate, afterTransmissionDate));

            if (beforeAllocationProcessDate != null && afterAllocationProcessDate != null)
                criteria.Add(Expression.Between("AllocationProcessDate", beforeAllocationProcessDate, afterAllocationProcessDate));

            if (Store.HasValue)
                criteria.CreateCriteria("Store", "Store").Add(Expression.Eq("Store.LocationNumber", Store.Value));

            return criteria.List<Core.Order>();
Justin Holbrook