Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

...

A Couple of noteworthy comments regarding the newly refactored code:

  • A reference to the RPCManager executing this request will be stored in DSRequest .This has to be done because, while the request is being.executed, access will be required to various items such as the NHibernate session, the DataSource object, etc - These items will all be provided by the RPCManager class 
  • The execute() method itself only loads the DataSource object then calls the DataSource's execute method for processing the request.

Refactoring DSResponse

In the DSResponse object, notice that it contains an object wrapped inside another just to mimic the structure of the JSON required by the front-end, with all the properties forwarded to the internal object. In order to make the DSResponse a bit simpler, remove this inner class and property, thereby making the DSResponse a simple container for properties. However, when serializing it out to JSON it will need use anonymous objects for serializing the response to the correct JSON format:

...

Code Block
virtual public DSResponse execute<T>(DSRequest<T> request)
{
    if (request == null)
    {
        return null;
    }

    if ("fetch".Equals(request.operationType))
    {
        return executeFetch<T>(request);
    }

    return null;
}

virtual public DSResponse executeFetch<T>(DSRequest<T> request)
{
    DSRequest<Dictionary<string, object>> req = request as DSRequest<Dictionary<string, object>>;
    DSRequest<supplyItem> itmreq = request.RpcManager.convertRequest<supplyItem>(req);

    DataSource ds = request.RpcManager.getDataSource(req.dataSource);

    var query = request.RpcManager.Session.CreateCriteria<supplyItem>();

    // build the criteria
    if (req.data.Keys.Count != 0)
    {
        foreach (string key in req.data.Keys)
        {
            Dictionary<string, object> field = ds.getField(key);

            // make sure the field is in the DataSource
            if (field != null)
            {
                // get the property value
                PropertyInfo pi = itmreq.data.GetType().GetProperty(key);
                object val = pi.GetValue(itmreq.data, null);

                string type = field["type"] as string;

                if (type.Equals("text") || type.Equals("link") || type.Equals("enum") ||
                    type.Equals("image") || type.Equals("ntext"))
                {
                    query.Add(Restrictions.Like(key, "%" + val + "%"));
                    break;
                }
                else
                {
                    query.Add(Restrictions.Eq(key, val));
                    break;
                }
            }
        }
    }

    // add sorting
    if (req.sortBy != null)
    {
        // add the sorting
        foreach (string column in req.sortBy)
        {
            // if column name is with -, then ordering is descending, otherwise ascending
            if (column.StartsWith("-"))
            {
                // if sort is descending, then we have to remove the '-' from the beginning to get te correct
                // column name
                query.AddOrder(Order.Desc(column.Substring(1)));
            }
            else
            {
                query.AddOrder(Order.Asc(column));
            }
        }
    }

    // create a response object
    DSResponse dsresponse = new DSResponse();

    // set start row and number of rows on the query itself
    if (req.endRow != 0)
    {
        query.SetMaxResults(req.endRow - req.startRow);
        query.SetFirstResult(req.startRow);
    }

    // get the requested number of objects
    var products = query.List<supplyItem>();

    // change projection to get the total number of rows
    // we need to clear the result range and the ordering for this to work
    query.SetProjection(Projections.RowCount());
    query.SetFirstResult(0);
    query.SetMaxResults(int.MaxValue);
    query.ClearOrders();

    // set total rows using the projection
    dsresponse.totalRows = (int)query.UniqueResult<int>();

    // set the response data
    dsresponse.data = products;
    dsresponse.startRow = req.startRow;
    dsresponse.endRow = dsresponse.startRow + products.Count();

    // sanity check, if no rows, return 0
    if (dsresponse.endRow < 0)
    {
        dsresponse.endRow = 0;
    }

    dsresponse.status = 0;

    return dsresponse;
}
  • At the beginning of the executeFatch() method, create an additional DSRequest object, one which has the data property as supplyItem (is the NHibernate entity object). Unlike the current DSRequest object it was called with, which has the data property set as a Dictionary<string, object>. This needs to be done as the request is deserialized in the RPCManager as a DSRequest<Dictionary<string, object>> object, and by creating an instance of DSRequest<supplyItem> the deserializer will take care of converting all the required fields to the right type as it is defined in the supplyItem object.Both representations are needed to know which fields were specified as filter parameters and deserialization to supplyItem does not provide this information, as the properties which are not present will be null or their default values. This would make it impossible to figure out which are the fields which are filtered by, and not just their default value. This approach prevents having to manually convert all of the required properties to the right type when creating the Criteria for filtering.

Another approach to use to prevent manual conversion is to use reflection to get and set the property values. Looking at the above code, you will notice the following:

...