none
Doesn't service operation support OData system query operators? RRS feed

  • Question

  • Hello everyone,

    I wrote some service operations because I wanted to use stored procedures.

    It works well, but there is a problem. The problem is that I cannot use any OData system query.

    For example, I cannot use $select, $filter and $top.

    Are there any ways to support OData system queries even when I use system operators?


    • Edited by byHesed Tuesday, December 4, 2012 8:21 AM typos
    Monday, December 3, 2012 6:03 PM

Answers

  • No - you can't. This is by design in OData currently. The response with these entities need to be able to include edit links, that is links back to these entities. But those links can't be constructed from a service operation since the runtime has no way to figure out the parameters to the service operation to get the desired entity. The only way it can make this work is to return a link to the entity set (the table) and the primary key for that entity. But in order for that it needs the entity set to be publicly available.

    You could intercept the query into the entity and block access that way, but unless done carefully this could make lot of clients unusable since they might send GET requests to those links in the original response, and so you would need to make sure those still work.

    Thanks,


    Vitek Karas [MSFT]

    • Marked as answer by byHesed Friday, December 7, 2012 12:56 PM
    Wednesday, December 5, 2012 12:31 PM
    Moderator

All replies

  • Hi,

    WCF DS supports query operators on top of service operation results but the service operation must fulfill certain requirements:

    - It must be a GET (not POST)

    - It must return IQueryable<T> (not IEnumerable)

    - The T in IQueryable<T> must be an entity type (so there must be an entity set for that entity).

    Some query operators are also allowed if the service operation returns a single T where T is an entity (for example $select will work then).

    Thanks,


    Vitek Karas [MSFT]

    Monday, December 3, 2012 6:28 PM
    Moderator
  • Hello Vitek,

    You have helped me a lot. I really appreciate your answer.


    My program seems that following only two first conditions.

    When I see the result of $metadata request, the data type is not an entity type, but a complex type.

    Can I change the complex type to an entity type? If it's possible, how should I do? If it's not, why is it impossible?

    P.S. I pasted my code related to a service operations to give you more ideas.


    ---

    1. The result of localhost:26282/OData.svc/$metadata

    ...

    <ComplexType Name="GetDimensionList_Result">
    <Property Name="DimensionCode" Type="Edm.String" Nullable="false" MaxLength="50"/>
    <Property Name="DimensionName_EN_" Type="Edm.String" Nullable="false" MaxLength="100"/>
    <Property Name="DimensionName_FR_" Type="Edm.String" Nullable="false" MaxLength="100"/>
    <Property Name="DimensionMetadata_EN_" Type="Edm.String" MaxLength="Max"/>
    <Property Name="DimensionMetadata_FR_" Type="Edm.String" MaxLength="Max"/>
    </ComplexType>

    ...

    ---

    2. A method body of the service operation

    [WebGet]

    public IQueryable<GetDimensionList_Result> GetDimensionList(string datasetCode)
    {
        return CurrentDataSource.GetDimensionList(datasetCode).AsQueryable();
    }

    ---

    3. a definition of GetDimensionList_Result

     [Serializable]
    [EdmComplexType(NamespaceName = "DatawarehouseModel", Name = "GetDimensionList_Result")]
    public class GetDimensionList_Result : ComplexObject
    {
        public GetDimensionList_Result();

        [EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
        public string DimensionCode { get; set; }

        [EdmScalarProperty(EntityKeyProperty = false, IsNullable = true)]
        public string DimensionMetadata_EN_ { get; set; }

        [EdmScalarProperty(EntityKeyProperty = false, IsNullable = true)]
        public string DimensionMetadata_FR_ { get; set; }

        [EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
        public string DimensionName_EN_ { get; set; }

        [EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
        public string DimensionName_FR_ { get; set; }

        public static GetDimensionList_Result CreateGetDimensionList_Result(string dimensionCode, string dimensionName_EN_, string dimensionName_FR_);
    }

    Tuesday, December 4, 2012 8:37 AM
  • This is EF's restriction - I don't think EF can map a result of a stored procedure as an entity type. In fact that would be pretty hard since entity type must have a unique key property (primary key), which can't be guaranteed for stored procedure results. OData itself also requires entity types to have key properties, so even if you would not use EF, you would still have to come up with a key property. This is necessary to support some of the query operations (like key lookup).

    Thanks,


    Vitek Karas [MSFT]

    Tuesday, December 4, 2012 8:48 AM
    Moderator
  • I added an EntityType by exposing another table that has the same structure with the table a service operation generates.

    Therefore, my service operation supports OData system query.

    Here is the part of my OData metadata.

    <EntitySet Name="OData_DatasetList" EntityType="DatawarehouseModel.OData_DatasetList"/>
    <FunctionImport Name="GetDatasetList" ReturnType="Collection(DatawarehouseModel.OData_DatasetList)" EntitySet="OData_DatasetList" m:HttpMethod="GET">
    <Parameter Name="datasetCode" Type="Edm.String"/>
    </FunctionImport>

    As you see, they use the same type, DatawarehouseModel.OData_DatasetList.

    However, I also want to hide the table exposed to add its EntityType.

    When I try to hide it, OData service gives me an error that I should make the table visible or hide the service operation.

    Can I hide the table I expose and only provide a service operation which has the same return type of the table?

    Wednesday, December 5, 2012 12:10 PM
  • No - you can't. This is by design in OData currently. The response with these entities need to be able to include edit links, that is links back to these entities. But those links can't be constructed from a service operation since the runtime has no way to figure out the parameters to the service operation to get the desired entity. The only way it can make this work is to return a link to the entity set (the table) and the primary key for that entity. But in order for that it needs the entity set to be publicly available.

    You could intercept the query into the entity and block access that way, but unless done carefully this could make lot of clients unusable since they might send GET requests to those links in the original response, and so you would need to make sure those still work.

    Thanks,


    Vitek Karas [MSFT]

    • Marked as answer by byHesed Friday, December 7, 2012 12:56 PM
    Wednesday, December 5, 2012 12:31 PM
    Moderator