Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return plain objects in entity framework for serialization

I have been trying out both Linq to Sql and EF in my ASP.NET MVC application. After switching to EF I realized my XML/JSON serialization output has extra cruft.

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

Instead I would just like my output to be:

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

My EF query to retrieve the object is:

Tests.First(t => t.Id == testId);
like image 523
aleemb Avatar asked Dec 09 '22 21:12

aleemb


2 Answers

You can shape the JSON result in your controller like this:

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

This will limit the DTO which is serialized to contain only the values you want.

Edit: As a paritial answer to your comment question; you can create a simpler PersonViewModel class (DTO) that you can map the properties to. As John Saunders mentioned in his answer Automapper is a nice way to simplify the copying of the property values out of the EF Person instance:

The modified Action method may look like this:

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

The only other option I can think of is to use reflection to modify the DataMemberAttributes on the Person entity to suppress the EntityKey property.

like image 96
Kris Avatar answered Feb 23 '23 04:02

Kris


Another approach to work around this is to use the JavascriptSerializer's ScriptIgnore attribute and create a partial class for the object in question, new'ing up the EntityKey, EntityState properties and adding a ScriptIgnore attribute to them:

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

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

When the Person class is serialized via JavascriptSerializer, it will ignore those properties. However, this would not be practical because EF uses the state info to keep track of objects and this would wreak havoc.

If there were a way to dynamically add properties, it would eliminate the need to override those properties just to add a [ScriptIgnore] attribute. But, since there is no way to dynamically add attributes, this solution may not be that useful.

like image 20
aleemb Avatar answered Feb 23 '23 05:02

aleemb