Question

In RIA Services (and probably other frameworks such as WCF Data Services) one can implement data services methods by supplying methods returning an IQuerably. For example:

IQueryable<Customer> GetCustomers()
{
    return this.DbContext.Customers.Where(c => !c.IsDeleted);
}

A query from the client can then supply an additional filter (among other things). Both the client-provided filter and the filter for returning only undeleted customers will be combined an sent to the database in SQL by entity framework (or whatever ORM is used).

Often entity framework isn't powerful enough to express the query one wants to write, in which case we have to go to linq to objects:

IQueryable<CustomerWithFluff> GetCustomers()
{
    var customers =
        this.DbContext.Customers
        .Include("FluffBits")
        .Where(c => !c.IsDeleted)
        .ToList();

    return
        from c in customers
        select new CustomerWithFluff()
        {
            CustomerName = c.Name,
            ComplexFluff = String.Join(", ", from b in c.FluffBits select b.FluffText)
        };
}

The sql to the database will now still contain the restriction on "IsDeleted", but not any further filter provided by a client: Those will be applied on the linq to objects level after all the data has already been fetched.

If I don't care to let the client filter on any of the data that I need to compose with linq-to-objects (only "ComplexFluff" in this example), is there a way to still allow filtering on the properties that are simply projected (only "CustomerName" in this example)?

Était-ce utile?

La solution

Yes there is, however is not as simple as one can expect. You have to override the

public override IEnumerable Query(QueryDescription queryDescription, out IEnumerable<ValidationResult> validationErrors, out int totalCount)

method, where you can get, in queryDescription.Query the actual query and Expression that is going to be executed against your Queryable (that is, what is being returned by queryDescription.Method.Invoke(this, queryDescription.ParamterValues)).

You can then get the expression sent by the client and pass it to your method (maybe as a reference to some sort of field in you domainService, don't forget that WCF Ria Services are instantianted at each call, i.e. like a regular wcf perCall instancing model) where you'll have to combine

var customers =
        this.DbContext.Customers
        .Include("FluffBits")
        .Where(c => !c.IsDeleted)

prior to the "ToList()" method call.

Not easy, but quite possible

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top