【问题标题】:Return plain objects in entity framework for serialization在实体框架中返回普通对象以进行序列化
【发布时间】:2010-10-17 12:52:15
【问题描述】:

我一直在我的 ASP.NET MVC 应用程序中尝试 Linq to Sql 和 EF。切换到 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);

【问题讨论】:

  • 我很想知道您是如何设法从 EF 对象获取 JSON 序列化的。我认为引用计数机制不兼容。我最终创建了一个匿名类型并将其序列化(基本上作为 DTO)
  • @Program.X,我写了一个适合我的过滤器,但我还没有在复杂的 EF 对象上尝试过。 aleembawany.com/2009/03/27/… 让我知道这是否适合您,以及您是否找到解决手头问题的更好方法。
  • 另外,如果您不在 .NET framework 3.5SP1/VS2008 SP1 上,您可能会遇到问题。

标签: linq-to-sql json entity-framework serialization poco


【解决方案1】:

您可以像这样在控制器中调整 JSON 结果:

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

这将限制被序列化的 DTO 只包含你想要的值。

编辑: 作为对您的评论问题的部分回答;您可以创建一个更简单的 PersonViewModel 类 (DTO),您可以将属性映射到该类。正如 John Saunders 在他的回答中提到的,Automapper 是一种简化从 EF Person 实例中复制属性值的好方法:

修改后的 Action 方法可能如下所示:

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

我能想到的唯一其他选择是使用反射来修改 Person 实体上的 DataMemberAttributes 以抑制 EntityKey 属性。

【讨论】:

  • Kris,我在发布问题后也偶然发现了这一点,但是,这里的问题是我必须重新组合 Person 对象。如果我向 Person 对象 Person.Age 添加一个新属性,我将不得不再次触摸此代码。有没有更优雅的方法?
  • 感谢您的示例,这是一个很好的起点,虽然非常酷,但仍需要维护映射视图。希望使用 .NET 4.0 和 T4 模板,事情会变得更容易。
【解决方案2】:

到目前为止,我发现的最佳技术涉及代码生成。我在一个使用 Service Factory 的项目中执行此操作,但您可以直接使用 T4 Text templates“手动”执行相同操作。

另外,请关注AutoMapper。它仍然很新,我认为它是新兴技术,但我希望它很快就会出现!

【讨论】:

  • AutoMapper 是一个有趣的项目,尽管这些都不适用于我,因为我想将 EF 对象转换为 POCO。
  • 您本身并不想要 POCO。你想要一个 DTO,AutoMapper 可以为它做映射。我没有直接推荐 Service Factory,尽管我在那里进行的代码生成实际上产生了 DTO 和翻译类。
  • 我开始发现 EF 的更大问题,例如缺乏对业务对象的关注和对持久性的无知(缺乏这些在这个问题中表现出来)。我找到了其他方法,但可能会弃船并恢复到 L2S 直到 EF 的 V2。
【解决方案3】:

解决此问题的另一种方法是使用 JavascriptSerializer 的 ScriptIgnore 属性并为相关对象创建部分类,新建 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] 属性就无需重写这些属性。但是,由于无法动态添加属性,因此这种解决方案可能没有那么有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-08-28
    • 2019-02-27
    • 2012-12-16
    相关资源
    最近更新 更多