Возврат простых объектов в рамках сущности для сериализации - PullRequest
4 голосов
/ 04 апреля 2009

Я пытался использовать Linq для Sql и EF в своем приложении ASP.NET MVC. После перехода на EF я понял, что мой вывод сериализации XML / JSON лишен смысла.

XML:

<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <EntityKey>
    <EntitySetName>Persons</EntitySetName>
    <EntityContainerName>PersonEntities</EntityContainerName>
    <EntityKeyValues>
      <EntityKeyMember>
        <Key>Id</Key>
        <Value xsi:type="xsd:int">1</Value>
      </EntityKeyMember>
    </EntityKeyValues>
  </EntityKey>
  <Id>1</Id>
  <Name>John</Name>
</Test>

JSON:

{"Id":1,"Name":"John","EntityState":2,"EntityKey"{"EntitySetName":"Persons","EntityContainerName":"PersonEntities","EntityKeyValues":[{"Key":"Id","Value":1}],"IsTemporary":false}}

Вместо этого я просто хотел бы, чтобы мой вывод был:

{"Id":1, "Name":"John"}

Мой EF-запрос для получения объекта:

Tests.First(t => t.Id == testId);

Ответы [ 3 ]

7 голосов
/ 04 апреля 2009

Вы можете сформировать результат JSON в вашем контроллере следующим образом:

public JsonResult Person(int id)
{
  var person = PersonRepository.FindByID(id);
  var result = new { Id = person.Id, Name = person.Name };
  return Json(result);
}

Это ограничит серию DTO, содержащую только те значения, которые вы хотите.

Edit: В качестве примитивного ответа на ваш комментарий к вопросу; Вы можете создать более простой класс PersonViewModel (DTO), которому вы можете сопоставить свойства. Как отметил Джон Сондерс в своем ответе, Automapper - хороший способ упростить копирование значений свойств из экземпляра EF Person:

Модифицированный метод Action может выглядеть так:

public JsonResult Person(int id)
{
  var person = PersonRepository.FindByID(id);
  var dto = Mapper.Map<Person, PersonViewModel>(person);
  return Json(dto);
}

Единственный другой вариант, который я могу придумать, - это использовать отражение, чтобы изменить атрибуты DataMemberAttributes в сущности Person для подавления свойства EntityKey.

5 голосов
/ 05 апреля 2009

Другой подход к решению этой проблемы - использовать атрибут ScriptIgnore JavascriptSerializer и создать частичный класс для рассматриваемого объекта, добавив новые свойства EntityKey, EntityState и добавив к ним атрибут ScriptIgnore:

public partial class Person
{
    [ScriptIgnore]
    public new System.Data.EntityKey EntityKey { get; set; }

    [ScriptIgnore]
    public new System.Data.EntityState EntityState { get; set; }
}

Когда класс Person сериализуется через JavascriptSerializer, он игнорирует эти свойства. Однако это нецелесообразно, поскольку EF использует информацию о состоянии для отслеживания объектов, что может привести к хаосу.

Если бы был способ динамического добавления свойств, это исключило бы необходимость переопределять эти свойства просто для добавления атрибута [ScriptIgnore]. Но, поскольку нет возможности динамически добавлять атрибуты, это решение может быть не очень полезным.

1 голос
/ 04 апреля 2009

Пока что лучшая техника, которую я нашел, включает генерацию кода. Я сделал это на одном проекте, который использовал Service Factory , но вы могли сделать то же самое "вручную", используя T4 Текстовые шаблоны напрямую.

Кроме того, следите за AutoMapper . Это все еще достаточно ново, и я считаю, что это новая технология, но я надеюсь, что она скоро появится!

...