OData / ModelBuilder

A project to generate Edm (Entity Data Model) from CLR types
19 stars 19 forks source link

Question: Vocabulary annotations for contained entity sets? #35

Open maximpashuk opened 6 years ago

maximpashuk commented 6 years ago

Interface IEdmEntitySet include interface IEdmVocabularyAnnotatable, so I can set, for example, optimistic concurrency properties for top-level entity set.

BUT, interface IEdmContainedEntitySet not include IEdmVocabularyAnnotatable, so I can't set optimistic concurrency properties for non-top level entity set.

Probably I am missing something, but element from top-level EntitySet and it child from selecondlevel ContainedEntitySet both can have concurrency properties.

Can somebody explain why contained entity set so restricted that them cannot be annotated?

maximpashuk commented 6 years ago

FYI: I have some issue search, and probably my question has some relations with issue https://github.com/OData/WebApi/issues/472

biaol-odata commented 6 years ago

@mikepizzo please follow up this issue with OASIS TC. Thanks.

maximpashuk commented 2 years ago

Recently updated my project to OData 8.0.8 and issue is still present in 2022.

Reproduce: just add contained entity with concurrency token (in my case user.ContainsMany(userProfiles), userProfile has concurrencyToken declared)

Later if I trying to patch userProfile and set If-Match header in my http request, but in ODataQueryOptions.IfMatch I can't see concurrencyToken, because it is not annotated correctly in edm model.

As a workaround I use following snippet, hope you understand my domain context

    public static IEdmModel AddUserProfileConcurrency(this IEdmModel model)
    {
        var users = model.EntityContainer.FindEntitySet("users");
        var user = users.EntityType();
        var profiles = (IEdmNavigationProperty) user.FindProperty("profiles");
        var profilesTarget = users.FindNavigationTarget(profiles);
        var profile = profilesTarget.EntityType();
        var concurrencyProperty = (IEdmStructuralProperty) profile.FindProperty("concurrency");

        var concurrencyProperties = model.GetAnnotationValue<ConcurrencyPropertiesAnnotation>(model) ??
                                    new ConcurrencyPropertiesAnnotation();
        concurrencyProperties[profilesTarget] = new[] {concurrencyProperty};

        model.SetAnnotationValue(model, concurrencyProperties);

        return model;
    }

If I just set .IsConcurrencyToken() on concurrency property, this simply doesn't work, ETagMessageHandler not worked correcly for contained entity sets.

@xuzhg please take a look, probably this issue should be transferred to https://github.com/OData/ModelBuilder repo, I not sure