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 与计算属性一起使用的方法。
关于如何克服这种情况的一些建议?
现在有一种软方法可以做到这一点,那就是使用注释在客户端和服务器之间构建合约。
在 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 查询此属性。