OData 只读属性

本文关键字:只读属性 OData | 更新日期: 2023-09-27 18:33:03

我有一个带有OData V4的WebAPI 2.2应用程序。我也在使用EF 6.1。

在我的一个实体中,我有一个计算属性:


public class Person 
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   
   // Calculated Property - No setter
   public string FullName 
   { 
        get { return FirstName + " " + LastName; }
   }
} 

为了向我的客户提供计算的属性,我需要在 OData 模型中注册

public static IEdmModel GetModel() 
{
    ODataModelBuilder builder = new ODataConventionModelBuilder();
    
    builder.Namespace = "NavigationServices";
    builder.EntityType<Person>;
    builder.EntityType<Person>()
        .Property(a => a.FullName); // Calculated Property
        
    return builder.GetEdmModel();
}
<小时 />

因此,当我在客户端获取数据时,每个对象都具有 Compute 属性。

但是,当我尝试创建 (POST) 新元素或更新 (PUT) 现有元素时,我的操作无法识别该元素并生成一个错误,指出它找不到该属性的"set 方法"。

我阅读了几篇关于 OData 中只读属性的文章(显然不受支持),但我找不到将 OData 与计算属性一起使用的方法。

关于如何克服这种情况的一些建议?

OData 只读属性

现在有一种软方法可以做到这一点,那就是使用注释在客户端和服务器之间构建合约。

在 V4 标准的核心词汇中,有这样一个术语:

<Term Name="Computed" Type="Core.Tag" DefaultValue="true" AppliesTo="Property">
    <Annotation Term="Core.Description" String="A value for this property is generated on both insert and update"/>
</Term>

在 Web API OData 的 WebConfig.cs 中,编写此类代码以将此类注释添加到您的属性:

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
var model = builder.GetEdmModel() as EdmModel;
model.SetVocabularyAnnotation(
    new EdmAnnotation(model.EntityContainer.FindEntitySet("People").EntityType().FindProperty("FullName"),
    new EdmTerm("Org.OData.Core.V1", "Computed", EdmPrimitiveTypeKind.Boolean),
    new EdmBooleanConstant(true)));

然后在您的数据中,它将如下所示:

<Annotations Target="V4Service.Models.Person/FullName">
    <Annotation Term="Org.OData.Core.V1.Computed" Bool="true"/>
</Annotations>

通过上述步骤,服务通告Person实体上的FullName属性由服务计算。然后,在 POST 和 PATCH 请求的控制器方法中,您可以拥有自己的逻辑,忽略客户端为 FullName 属性发送的任何值并计算自己的逻辑。

我不确定您使用的是哪个客户端。如果使用适用于 .NET 的 OData 客户端,则下一版本中将支持获取批注值。如果您不介意直接使用 EdmLib,则已经添加了注释值检索支持。

你是对的,OData目前不支持read-only properties

但是,它支持read-only entities

或者,您可以通过添加一个对您的property没有任何作用的setter来欺骗OData

public string FullName
{ 
    get
    {
        return FirstName + " " + LastName;
    }
    set
    {
        // do nothing
    }
}

以下是将entity设置为只读的方式:

public class Northwind : DataService<NorthwindEntities>
{
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("Customers", EntitySetRights.AllRead);
    }
}

在您的实体中,您需要一个 [NotMapped] 数据注释:

[NotMapped]
public string FullName => $"{FirstName} - {LastName}";

在 OData 配置中:

builder.EntityType<Person>;
builder.StructuralTypes.First(t => t.ClrType == typeof(Person))
                .AddProperty(typeof(Person).GetProperty(nameof(Person.FullName)));

这样你就不需要空的二传手了。

可以使用数据库计算属性而不是类计算属性。

本文介绍 EF 和数据库计算属性。与本文相比,我在示例代码中看到的一个区别是,您的属性中没有任何 setter。如果将媒体资源设置为将自动访问器与专用集一起使用

public string FullName { 
    get;
    private set; 
}

然后将数据库中的列创建为计算列。

ALTER TABLE dbo.Users ADD FullName AS FirstName + ' ' + LastName

作为附加功能,您将能够使用 odata 和 Linq 查询此属性。