简体   繁体   中英

How can I get IEdmEntityTypeReference.Key() to return keys in the correct order?

I'm working with OData, something I'm not too familiar with. When OData attaches an entity to the Context in the DataServiceContext class, they set the .Identity property using ODataResourceMetadataBuilder.

ODataResourceMetadataBuilder entityMetadataBuilder = this.GetEntityMetadataBuilderInternal(descriptor);

descriptor.EditLink = entityMetadataBuilder.GetEditLink();
descriptor.Identity = entityMetadataBuilder.GetId();

This goes through a series of OData classes starting with ConventionalODataEntityMetadataBuilder.GetId() , that eventually gets to where the CompositeKey is created in OData's DataServiceUrlKeyDelimiter

internal void AppendKeyExpression(IEdmStructuredValue entity, StringBuilder builder)
{
    Debug.Assert(entity != null, "entity != null");
    Debug.Assert(builder != null, "builder != null");

    IEdmEntityTypeReference edmEntityTypeReference = entity.Type as IEdmEntityTypeReference;
    if (edmEntityTypeReference == null || !edmEntityTypeReference.Key().Any())
    {
        throw Error.Argument(ErrorStrings.Content_EntityWithoutKey, "entity");
    }

    // Problem occurs here - edmEntityTypeReference.Key() has the keys in the wrong order.
    this.AppendKeyExpression(edmEntityTypeReference.Key().ToList(), p => p.Name, p => GetPropertyValue(entity.FindPropertyValue(p.Name), entity.Type), builder);
}

The keys are defined in my class using Key Annotations

public class MyClass
{
    [Key, Column(Order = 0)]
    public Guid CompositeKeyB { get; set; }

    [Key, Column(Order = 1)]
    public Guid CompositeKeyA { get; set; }
}

Note that the keys are alphabetically backwards.

When the above code runs to set the .Identity field, it is giving me the keys in alphabetical order, not in the order I specified in the Data Annotations.

This is a problem because when an entity is retrieved, the Keys are in the correct order so it has a different .Identity property and is seen as a separate instance than the attached instance. This means that it doesn't update the Attached entity with the new data, and also that a second copy of the entity gets created in the Context.

Is there an easy way to correct this, or am I stuck with writing my own code to get the Keys in the correct order using Reflection? I do not currently see a way of finding the Order value in the IEdmStructuralProperty property that is returned from IEdmEntityTypeReference.Key() .

The issue was occurring because in the ClientEdmModel.GetOrCreateEdmTypeInternal method it is ordering the properties by name before sorting them into key and non-key properties.

// Problem is the .OrderBy in this line of code
foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/edmBaseType != null).OrderBy(p => p.Name))
{
    IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
    loadedProperties.Add(edmProperty);

    if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
    {
        Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
        Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive || edmProperty.Type.TypeKind() == EdmTypeKind.Enum, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive || edmProperty.Type.TypeKind() == EdmTypeKind.Enum");
        loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
    }
}

The solution we used was to apply the original sorting to composite key properties afterwards, although a potential solution could also be to remove the .OrderBy(p => p.Name) from the foreach loop. I'm not sure if this would cause other problems though, so it seems safest to just re-apply the key sort order afterwards for composite keys.

if (loadedKeyProperties.Count > 1)
{
    var orderedKeyPropertyNames = keyProperties.Select(k => k.Name).ToList();
    loadedKeyProperties = loadedKeyProperties.OrderBy(k => orderedKeyPropertyNames.IndexOf(k.Name)).ToList();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM