Processing Search Results

Processing Results for multiple POCO objects


The code fragment below shows how we processed the search results in earlier samples.

         foreach (Document doc in res.Documents)
            {           
                CustomerOrders _order = new CustomerOrders()
                {
                    id = doc.Id,
                    score = doc.Score,
                    customerName = (string)doc["customerName"],
                    address = (string)doc["address"],
                    customerID = (string)doc["customerID"],
                    productName = (string)doc["productName"],
                    extendedPrice = Convert.ToDecimal(doc["extendedPrice"]),
                    //.. etc
                };
                customerOrdersList.Add(_order);   
            }
            return customerOrdersList;

The disadvantage of this approach is that it is bound to the CustomerOrders class.  If you have several classes to which you cast your search results, you'll have to repeat the same kind of code for every one of those classes.

We can improve the code to handle multiple classes by using a generic method to process/cast the results.  The trick is let the POCO classes inherit from the same base as shown below for the CustomerOrders class.

public class DocCommon
    {
        public string id { get; set; }
        public double score { get; set; }
    }
     public class CustomerOrders : DocCommon
   {
        public string customerID { get; set; }
        public string customerName { get; set; }
        public string address { get; set; }
        
        //etc..
   }
CustomerOrders fragment

Armed with this definition, we can then use the sample code below to call a generic method to cast the search results.

        [HttpGet]
        [Route("api/search/orders/redis")]
        public async Task<List<CustomerOrders>> SearchRedisOrdersData()
        {
            searchString = "Vins";
            IDatabase db =   _connectionMultiplexer.GetDatabase();

            NRediSearch.Query query = new NRediSearch.Query(searchString);
            query.WithPayloads = true;

            SearchResult res = await _rediSearchClient.SearchAsync(query);
            
            List<CustomerOrders> appDocs = (from doc in res.Documents
                  select GetDocData<CustomerOrders>(doc)).ToList();            
            return appDocs;
        }
Using Generic Method to Process Results

The magic happens in lines #13-14, where we use the generic method GetDocData shown below to cast the search results.

Note: the generic method is constrained to DocCommon.

        public T GetDocData<T>(Document document) where T: DocCommon    
        {
            IEnumerable<KeyValuePair<string, RedisValue>> docRecords = document.GetProperties();
            
            string jsonDocRecord = JsonConvert.SerializeObject(docRecords);
            T record = JsonConvert.DeserializeObject<T>(jsonDocRecord);
            record.id = document.Id;
            record.score = document.Score;
            return record;
        }
--Generic Method for Processing RediSearch Results