Print Page | Close Window

PredicateDescription.PropertyName no longer available and can't instantiate CompositePredicateDescription directly.

Printed From: IdeaBlade
Category: DevForce
Forum Name: DevForce 2010
Forum Discription: For .NET 4.0
URL: http://www.ideablade.com/forum/forum_posts.asp?TID=2957
Printed Date: 13-May-2026 at 6:18pm


Topic: PredicateDescription.PropertyName no longer available and can't instantiate CompositePredicateDescription directly.
Posted By: gcpeters
Subject: PredicateDescription.PropertyName no longer available and can't instantiate CompositePredicateDescription directly.
Date Posted: 12-Sep-2011 at 9:40am
I recently upgraded my DevForce installation to v6.1.2.0 and after rebuilding my Model and attempting to compile my assemblies, I received two errors.
===============================================
IEntityQuery<Account> searchQuery = SourceRepository.AccountRepo.CreateSearch();
Collection<PredicateDescription> subSearch = new Collection<PredicateDescription>();
PredicateDescription accountSearch = PredicateBuilder.Make(typeof(Account), "DealerID", FilterOperator.IsEqualTo, FilterDealerRecord.ID);
CompositePredicateDescription compositeSubSearch = null;
if (!string.IsNullOrEmpty(SearchAccountName))
subSearch.Add(PredicateBuilder.Make(typeof(Account), "Name", FilterOperator.Contains, SearchAccountName));
if (!string.IsNullOrEmpty(SearchAccountNumber))
subSearch.Add(PredicateBuilder.Make(typeof(Account), "AccountNo", FilterOperator.Contains, SearchAccountNumber));
if (subSearch.Count > 0)
{
foreach (PredicateDescription pd in subSearch)
{
if (null != compositeSubSearch)
compositeSubSearch = compositeSubSearch.Or(pd);
else
ERROR ===> compositeSubSearch = new CompositePredicateDescription(pd.InstanceType, pd.PropertyName, pd.FilterOperator, pd.Value);
}
}
if (null != compositeSubSearch)
searchQuery = searchQuery.Where(accountSearch.And(compositeSubSearch));
else
searchQuery = searchQuery.Where(accountSearch);
SourceRepository.AccountRepo.SearchFor(searchQuery, null, pDefaultSuccess, pDefaultFailure, (pForceRefresh) ? LYNX.Infrastructure.CONSTANTS.QueryStrategies.QS_WithDataSourceAndCacheFetch_OverwriteChanges : LYNX.Infrastructure.CONSTANTS.QueryStrategies.QS_WithOptimizedFetch_PreserveChanges);
===============================================
I was previously using 6.0.7 and this code worked fine.
Basically I display a list of account on a grid. I provide a single "Search Field" with a couple of checkboxes that allows the user to tell the system to "Not include" certain fields in the search.
On this particular screen, I always have to include a filter for the "DealerID" so that I don't return accounts for any other dealer in the system. My query is simply WHERE DealerID == <ID> AND (Name.Contains(<searchCriteria>) OR AccountNo.Contains(<searchCriteria>)). This was my first implementation and it seemed to work just fine until I updated the DevForce libraries.
Error #1: On the PredicateDescription, the PropertyName is no longer exposed.
Error #2: I'm no longer able to construct an instance of the CompositePredicateDescription to use as a "starting point" to construct my OR criteria.
Maybe my original implementation wasn't the best approach, but can someone suggest a better approach or solution to the one I've listed above. I have my Repository methods currently designed to accept an IEntityQuery so I would like to continue to use this approach so that I don't have to refactor all of my repository classes and consumers.
Thanks,
George



Replies:
Posted By: sbelini
Date Posted: 14-Sep-2011 at 4:30pm
Hi George,
 
CompositePredicateDescription no longer has a constructor, but you still can build it using extension methods.
 
I recognize that in your scenario this change makes things a little more complicated. I am checking with our senior engineer the reason for such change and will follow up.
 
In the meantime, here's an workaround:
 
  if (subSearch.Count > 0) {
    if (subSearch.Count == 1) {
      searchQuery = searchQuery.Where(employeeSearch.And(subSearch.First()));
    } else {
      compositeSubSearch = subSearch[0].Or(subSearch[1]);
      for (int i = 2; i < subSearch.Count; i++) {
        compositeSubSearch = compositeSubSearch.Or(subSearch);
      }
      searchQuery = searchQuery.Where(accountSearch.And(compositeSubSearch));
    }
  } else {
    searchQuery = searchQuery.Where(accountSearch);
  }

 Sorry for the inconvenience,

   Silvio.



Posted By: gcpeters
Date Posted: 27-Sep-2011 at 7:16am
Thanks for the update. 
The solution you offered is similar to the one that I ended up creating.  In my opinion it's a little more code and not as clean as I originally had before the constructor was removed.
 
If the senior engineer can clear up why there was a need to remove the constructor and no longer expose the PropertyName through the PredicateDescription, I'm curious.
 
Thanks,
George


Posted By: sbelini
Date Posted: 28-Sep-2011 at 3:48pm
Hi George,

I've checked with our senior engineer and here's his clarification:

"

The major reason for changing the PredicateDescription was that we were getting a lot of request to broaden the range of possible predicates that we could support as well as to extend our dynamic query support in general with projections, grouping and aggregate operators.  Much of this is described here:  http://drc.ideablade.com/xwiki/bin/view/Documentation/dynamic-queries - http://drc.ideablade.com/xwiki/bin/view/Documentation/dynamic-queries

One of the most obvious changes was that we realized that a ‘property name’ was just the simplest example of the idea of ‘projecting’ data out of a type. Another example was a ‘nested property name’, i.e. customer.Address.City or even a projection that involves a method call i.e. “customer.Orders.First().Freight”.  We also wanted to use this same concept not just in the PredicateDescription but also more generally anywhere within a dynamic query where a projection was needed.  We decided to call our implementation of this a ProjectionSelector.  So now a PredicateDescription can use a ProjectionSelector on either side of a FilterOperator, the new dynamic ‘Select’ operator uses ProjectionSelectors to describe selection criteria, the dynamic ‘GroupBy’ operator uses ProjectionSelectors to describe grouping criteria.

In making these changes we were able to keep all of our PredicateDescription constructors completely backward compatible but did remove ctors from the CompositePredicateDescription in favor of extension methods or static methods on the PredicateBuilder class to perform the same task. This change was simply to minimize the number of ways of accomplishing the same task.  So you can still compose your CompositePredicateDescription in either of the following ways.

      var expr1 = new PredicateDescription(typeof(Product), "UnitPrice"FilterOperator.IsGreaterThanOrEqualTo, 24);
      var expr2 = new PredicateDescription(typeof(Product), "Discontinued"FilterOperator.IsEqualTo, true);
      var expr3 = new PredicateDescription(typeof(Product), "Id"FilterOperator.IsNotEqualTo, 0);
      var expr123 = expr1.And(expr2).And(expr3);
or
      var expr123 = PredicateBuilder.And(expr1, expr2, expr3);
 
There are, of course ‘Or’ variants of each of these apis.

"


below are some other examples showing other uses for a ProjectionSelector:


Compare two properties of an object  

 var ps1 = new ProjectionSelector("CompanyName");

 var ps2 = new ProjectionSelector("City");
 var pd = new PredicateDescription(ps1, FilterOperator.StartsWith, ps2);
Using Projections with a method call.

 var rootQuery = EntityQuery.Create(typeof(Customer), _em1);

 var ps = new ProjectionSelector"OrderSummaries.FirstOrDefault().Freight""freight" );
 var query = query.Select(pps);
Complex query with aggregate ‘Any’ operator
// dynamic query for -> OrderSummaries.Where( os => os.OrderDetails.Any( od => od.Product.ProductName.Contains(“Chai’) && od.UnitPrice > 3)
 var pd1 = new PredicateDescription(typeof(OrderDetail), "Product.ProductName"FilterOperator.Contains, "Chai");
 var pd2 = new PredicateDescription(typeof(OrderDetail), "UnitPrice"FilterOperator.IsGreaterThanOrEqualTo, 3);
 var pd3 = pd1.And(pd2);
 var baseQuery = EntityQuery.Create(typeof(OrderSummary), _em1);
 var pd4 = new PredicateDescription(typeof(OrderSummary), "OrderDetails"FilterOperator.Any, pd3);
 var finalQuery = baseQuery.Where(pd4);
"
Regards,
    Silvio.


Posted By: gcpeters
Date Posted: 12-Oct-2011 at 12:15pm
Thanks for taking the time to provide such a detailed explanation and alternate solutions.
 
It's very difficult while you're knee deep in building a large scale application to keep up and research the latest changes provided to 3rd party libraries.  Some of them may end up simplifying or providing a new approach to implementing many of the logic in the current project but you never seem to find enough time to refactor it utilizing the new and improved approach.
 
I appreciate you recapping the reasons for the change, how it might benefit me and providing some examples rather than having me click through pages and pages of links to "try' and figure out the benefits.
 
Thanks,
George Peters



Print Page | Close Window