简体   繁体   English

如何让 IEdmEntityTypeReference.Key() 以正确的顺序返回键?

[英]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.我正在使用 OData,我不太熟悉。 When OData attaches an entity to the Context in the DataServiceContext class, they set the .Identity property using ODataResourceMetadataBuilder.当 OData 将实体附加到DataServiceContext class 中的上下文时,他们使用 ODataResourceMetadataBuilder 设置.Identity属性。

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这经历了一系列从ConventionalODataEntityMetadataBuilder.GetId()开始的 OData 类,最终到达在 OData 的DataServiceUrlKeyDelimiter中创建 CompositeKey 的位置

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键是在我的 class 中使用键注释定义的

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.当上面的代码运行以设置.Identity字段时,它按字母顺序给我键,而不是按我在数据注释中指定的顺序。

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.这是一个问题,因为当检索实体时,键的顺序正确,因此它具有不同的.Identity属性,并且被视为与附加实例不同的单独实例。 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() .我目前看不到在从IEdmEntityTypeReference.Key()返回的IEdmStructuralProperty属性中查找 Order 值的方法。

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.之所以出现此问题,是因为在ClientEdmModel.GetOrCreateEdmTypeInternal方法中,它会先按名称对属性进行排序,然后再将它们分类为键属性和非键属性。

// 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.我们使用的解决方案是随后将原始排序应用于复合键属性,尽管潜在的解决方案也可能是从 foreach 循环中删除.OrderBy(p => p.Name) 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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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