simple-odata-client / Simple.OData.Client

MIT License
331 stars 197 forks source link

Have trouble processing entities with enum properties #412

Open 0x7a68 opened 7 years ago

0x7a68 commented 7 years ago

Hi,

I'm new to this library and I was trying to insert an entity with enum parameter using dynamic syntax.

var x = ODataDynamic.Expression;
var result = oDataClient.For(x.BusinessPartners)
        .Set(x.CardCode = "c2", x.CardName = "customer c2", x.CardType = "cCustomer")
        .InsertEntryAsync()
        .Result;

Related metadata:

<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
    <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
        <Schema Namespace="SAPB1" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
            ...
            <EntityType Name="BusinessPartner">
                <Key>
                    <PropertyRef Name="CardCode"/>
                </Key>
                <Property Name="CardCode" Nullable="false" Type="Edm.String"/>
                <Property Name="CardName" Type="Edm.String"/>
                <Property Name="CardType" Type="SAPB1.BoCardTypes"/>
                ...
            </EntityType>

            ...
            <EnumType Name="BoCardTypes">
                <Member Name="cCustomer"/>
                <Member Name="cSupplier"/>
                <Member Name="cLid"/>
            </EnumType>
            ...
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

And I got an ODataException: A primitive value was specified; however, a value of the non-primitive type 'SAPB1.BoCardTypes' was expected.

After that, I tried x.CardType = x.SAPB1.BoCardTypes.cCustomer and x.CardType = x.BoCardTypes.cCustomer but also failed.

I went through the tutorial, but most of the examples are typed syntax. And I checked dynamic tests in Simple.OData.Client.Tests.Net40, but all test are not related to enum. So is there any way to work with enum parameters using dynamic syntax?

Thanks!

object commented 7 years ago

Hi, sorry for the late response.

I believe you should be able to achieve this with dynamic code, look at Simple.OData.Client.Tests.Core project, in particular the file DynamicExpressionTests. Here are some examples:

    [Fact]
    public void FilterWithEnum()
    {
        var x = ODataDynamic.Expression;
        var filter = x.Address.Type == AddressType.Corporate;
        Assert.Equal(string.Format("Address/Type eq {0}", FormatSettings.GetEnumFormat(AddressType.Corporate, typeof(AddressType), "NorthwindModel")),
            filter.AsString(_session));
    }

    [Fact]
    public void FilterWithEnum_LocalVar()
    {
        var x = ODataDynamic.Expression;
        var addressType = AddressType.Corporate;
        var filter = x.Address.Type == addressType;
        Assert.Equal(string.Format("Address/Type eq {0}", FormatSettings.GetEnumFormat(AddressType.Corporate, typeof(AddressType), "NorthwindModel")),
            filter.AsString(_session));
    }

    [Fact]
    public void FilterWithEnum_Const()
    {
        var x = ODataDynamic.Expression;
        const AddressType addressType = AddressType.Corporate;
        var filter = x.Address.Type == addressType;
        Assert.Equal(string.Format("Address/Type eq {0}", FormatSettings.GetEnumFormat(AddressType.Corporate, typeof(AddressType), "NorthwindModel")),
            filter.AsString(_session));
    }

Hope this helps!

0x7a68 commented 7 years ago

Hi, thank you for your reply.

I found that the problem is more than dynamic codes. It seems like the client has trouble processing entities with enums of my OData Service.

To retrieve an entity with enums:

        public dynamic RetrieveBusinessPartnerByKey()
        {
            var businessPartner = oDataClient
                .For(exp.BusinessPartners)
                .Key("c1")
                .FindEntryAsync()
                .Result;
            return businessPartner;
        }

I could see from Fiddler that the client correctly send a GET request and receive an expected response. However, the codes still throw an ODataException: An internal error 'ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind' occurred.

As described in my previous post, an ODataException: A primitive value was specified; however, a value of the non-primitive type 'SAPB1.BoCardTypes' was expected. was raised when I tried to insert an entity with enum properties. And no HTTP request was sent to server.

But performing CRUD operations on an entity without any enum properties could work well.

When I work with TripPin V4 service, everything is fine. I wonder what makes the difference between TripPin service and my OData Service.

object commented 7 years ago

But did you try to change the syntax of the code that uses enums similar to how it's written in the test code I showed you above? I believe the problem is in formatting of the enums that is sent to dynamic provider. You can also try using non-dynamic, typed code and see if it works with your service, just to compare with.

0x7a68 commented 7 years ago

Sorry for not mentioning it, but I believe this problem has little to do with the syntax. I tried using untyped, typed, dynamic and even basic API. But all of them cannot work with my service.

As mentioned above, when I was trying to retrieving an entity with enums, the client could send a GET request and receive an expected response, no matter what syntax did I use. But an ODataException: An internal error 'ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind' occurred.

When I was trying to insert or update an entity with enums, if I didn't assign values to enum properties(they are nullable), the POST request could be sent and the response indicated that the entity was created. But still, an ODataException: An internal error 'ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind' occurred.

But if I tried to assign values to enum properties before insert or update an entity, an ODataException: An internal error 'ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind' occurred.

However, everything works well with TripPin V4 service.

In my conclusion, if I don't assign values to enums, the client could send HTTP requests and get expected responses correctly (I could see this process with Fiddler). But it has some trouble parsing the response content and it would raise an internal error 'ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind'. If I try to assign values to enums before query, the ODataException A primitive value was specified; however, a value of the non-primitive type 'SAPB1.BoCardTypes' was expected occurs and no HTTP request would be sent to server.

object commented 7 years ago

Strange. Since you pasted part of your metadata I can try to reproduce this scenario on my machine and see what's going on.

muzzammilnagda commented 1 year ago

Can I know that is the issue mentioned above is resolved? As I am also facing the issue while working with Enum in simple O Data client.