OData只读属性

时间:2014-12-03 16:53:59

标签: c# entity-framework odata asp.net-web-api

我有一个带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();
    }

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

但是,当我尝试创建(POST)新元素或更新(PUT)现有元素时,我的操作无法识别该元素并生成错误,指出它没有找到“set method”for财产。

我在OData上阅读了几篇关于只读属性的帖子(显然不支持),但是我没有找到一种方法来使用具有计算属性的OData。

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

4 个答案:

答案 0 :(得分:7)

现在有一种简单的方法可以使用注释在客户端和服务器之间建立合同。

Core vocabulary of the V4 standard中,有一个这样的术语:

<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>

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

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

答案 1 :(得分:4)

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

但是,它支持read-only entities

或者,您可以通过添加OData来欺骗setterproperty对您的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); } } 设置为只读的方式:

{{1}}

答案 2 :(得分:1)

在您的实体中,您需要一个 [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)));

这样你就不需要空的 setter。

答案 3 :(得分:0)

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

This article describes EF and database computed properties.我在示例代码中看到的与文章相比的一个区别是,您的财产中没有任何二传手。如果将属性设置为使用具有私有集的自动访问者

public string FullName { 
    get;
    private set; 
}

然后在数据库中创建列作为计算列。

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

作为额外的加号,您可以使用odata和Linq查询此属性。