none
$select and $expand in a single query

    Question

  • I'm currently writing a custom data service using dictionaries. 

    I would like to allow for a $select and $expand to co-exist in a single query, but currently it looks like the data services doesn't allow for it. Is there a way to accomplish this or is a limitation of the framework?

    I have written a custom IDataServiceQueryProvider and IExpandProvider. When I try to do a query with $select and $expand I get an exception back saying I need to implement IProjectionProvider, but IProjectionProvider is an internal interface ("The service does not expose IProjectionProvider interface which is required when projection is requested")

    Monday, July 5, 2010 9:17 AM

Answers

  • Hi,

    ExpandedWrapper types are public although they do live in namespace called Internal and are not visible in intellisense. This is intentional since most people will never use them and those who implement custom providers (like you) are experienced enough to don't really mind :-).

    As for the projections the $select sort of overrides the $expand. Meaning that if the $select doesn't specify any property from the expanded entity, the expansion will be ignored (as no data from it would be used anyway). If you want a query which returns just a Name of the product, but the entire Category entity it should look like: /Products?$expand=Category&$select=Name,Category/*

    You can also choose only certain properties from the expanded entity like this: /Products?$expand=Category&$select=Name,Category/ID

    To make the projections easier for you I just posted a description of the expressions generated when simple projections are used here: http://blogs.msdn.com/b/vitek/archive/2010/07/07/data-services-expressions-part-8-projections.aspx. It's only about projections, so if you start mixing expansion and projections it will get more complicated, but it should get you at least started in the right direction.

    Thanks,


    Vitek Karas [MSFT]
    Wednesday, July 7, 2010 3:45 PM
    Moderator

All replies

  • Hi,

    The exception string is a bug. Originally we wanted to expose the projection provider interface, but it turns out that most implementations don't need that and can easily rely on the implementation provided by the product. So we made it internal.

    The problem is, that the IExpandProvider interface does not contain support for projections ($select), so if you implement it, the product tries to use it, but it can't if there are any projections in the query.

    Instead, you can leave both expansions and projections up to the product's implementation by not implementing the IExpandProvider. Then all queries will work, your query provider will get a  LINQ expression tree with the query.

    If you have all your data in memory in dictionaries, it is very easy to support such queries, because LINQ to Objects supports them just fine. If you use different type of provider, then it might be more tricky as some of the queries generated when both expand and select are used can be quite complex.

    Without knowing more details about your provider, I can't really suggest any other approach.

    Thanks,


    Vitek Karas [MSFT]
    Monday, July 5, 2010 1:12 PM
    Moderator
  • I'm using Dictionaries, but the data isn't in memory, I load it dynamically from a backend store. I use an ExpressionVisitor to build queries to access the backend store.

    If I don't provide an IExpandedProvider and have a query like "Products?$expand=Category" then it expects a ExpandedWrapper<Dictionary> as the return type from the IDataServiceQueryProvider, I'm not sure if there is a way that I can create an ExpandedWrapper<Dictionary>; it's also internal.

    And if I have a query like "Products?$expand=Category&$select=Name" then it goes to my IDataServiceQueryProvider, but the expression doesn't include any of the expansion info and even if I do include the expansion data in the result (by  hard coding it for the test) it still doesn't return it.

    Monday, July 5, 2010 1:47 PM
  • Hi,

    ExpandedWrapper types are public although they do live in namespace called Internal and are not visible in intellisense. This is intentional since most people will never use them and those who implement custom providers (like you) are experienced enough to don't really mind :-).

    As for the projections the $select sort of overrides the $expand. Meaning that if the $select doesn't specify any property from the expanded entity, the expansion will be ignored (as no data from it would be used anyway). If you want a query which returns just a Name of the product, but the entire Category entity it should look like: /Products?$expand=Category&$select=Name,Category/*

    You can also choose only certain properties from the expanded entity like this: /Products?$expand=Category&$select=Name,Category/ID

    To make the projections easier for you I just posted a description of the expressions generated when simple projections are used here: http://blogs.msdn.com/b/vitek/archive/2010/07/07/data-services-expressions-part-8-projections.aspx. It's only about projections, so if you start mixing expansion and projections it will get more complicated, but it should get you at least started in the right direction.

    Thanks,


    Vitek Karas [MSFT]
    Wednesday, July 7, 2010 3:45 PM
    Moderator