繁体   English   中英

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

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

我正在使用 OData,我不太熟悉。 当 OData 将实体附加到DataServiceContext class 中的上下文时,他们使用 ODataResourceMetadataBuilder 设置.Identity属性。

ODataResourceMetadataBuilder entityMetadataBuilder = this.GetEntityMetadataBuilderInternal(descriptor);

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

这经历了一系列从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);
}

键是在我的 class 中使用键注释定义的

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

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

请注意,这些键按字母顺序向后排列。

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

这是一个问题,因为当检索实体时,键的顺序正确,因此它具有不同的.Identity属性,并且被视为与附加实例不同的单独实例。 这意味着它不会使用新数据更新附加实体,并且实体的第二个副本会在上下文中创建。

有没有一种简单的方法来纠正这个问题,还是我坚持编写自己的代码来使用反射以正确的顺序获取键? 我目前看不到在从IEdmEntityTypeReference.Key()返回的IEdmStructuralProperty属性中查找 Order 值的方法。

之所以出现此问题,是因为在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);
    }
}

我们使用的解决方案是随后将原始排序应用于复合键属性,尽管潜在的解决方案也可能是从 foreach 循环中删除.OrderBy(p => p.Name) 不过,我不确定这是否会导致其他问题,因此之后为复合键重新应用键排序顺序似乎是最安全的。

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