Свойство OData для чтения

У меня есть приложение WebAPI 2.2 с OData V4. Также я использую 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 Model

    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) новый элемент или Update (PUT) существующий, мое действие не распознает элемент и генерирует ошибку, говорящую, что он не находит "метод установки" для свойство.

Я прочитал пару сообщений о свойствах только для чтения в OData (видимо, не поддерживается), но я не нашел способ использовать OData с вычисленными свойствами.

Некоторые советы о том, как преодолеть эту ситуацию?

Ответ 1

Теперь есть мягкий способ сделать это, чтобы построить контракт между клиентом и сервером с помощью аннотаций.

В Основной лексике стандарта 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>

В приведенных выше шагах служба сообщает, что служба FullName на объекте Person вычисляется службой. Затем в методах контроллера для запросов POST и PATCH вы можете иметь собственную логику игнорирования любого значения, отправленного клиентом для свойства FullName, и вычислить свой собственный.

Я не уверен, какой клиент вы используете. Если вы используете OData Client для .NET, наша поддержка получения значений аннотаций будет в нашей следующей версии. Если вы не против использования EdmLib напрямую, поддержка поиска значений аннотаций уже добавлена.

Ответ 2

Вы правы, OData не поддерживает read-only properties в это время.

Однако он поддерживает read-only entities.

Или вы можете обмануть OData, добавив setter, который ничего не делает для вашего property.

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);
    }
}

Ответ 3

Вы можете использовать вычисляемое свойство базы данных, а не свойство класса.

В этой статье описываются свойства EF и базы данных. Одно отличие, которое я вижу в вашем примере кода по сравнению с этой статьей, заключается в том, У вас есть сеттер в вашей собственности. Если вы установите для своего свойства использование автоматических аксессуаров с частным набором

public string FullName { 
    get;
    private set; 
}

Затем создайте столбец в базе данных как вычисленный столбец.

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

В качестве дополнительного плюса вы сможете запросить это свойство, используя odata и Linq.