4

我想将实体框架自我跟踪实体完整对象图(一对多关系中的父+子)序列化为 Json。

对于序列化,我使用ServiceStack.JsonSerializer

这就是我的数据库的样子(为简单起见,我删除了所有不相关的字段):

ERD

我以这种方式获取完整的个人资料图:

public Profile GetUserProfile(Guid userID)
{
    using (var db = new AcmeEntities())
    {
        return db.Profiles.Include("ProfileImages").Single(p => p.UserId == userId);
    }
}

问题是试图序列化它:

Profile profile = GetUserProfile(userId);
ServiceStack.JsonSerializer.SerializeToString(profile);

产生一个StackOverflowException. 我相信这是因为 EF 提供了一个无限模型,将序列化程序搞砸了。也就是说,我可以在技术上调用:profile.ProfileImages[0].Profile.ProfileImages[0].Profile ...等等。

如何“展平”我的 EF 对象图或以其他方式防止ServiceStack.JsonSerializer 遇到堆栈溢出情况?

注意:我不想将我的对象投影到匿名类型(如这些 建议),因为这会引入非常长且难以维护的代码片段)。

4

3 回答 3

9

您有相互矛盾的顾虑,EF 模型针对将您的数据模型存储在 RDBMS 中进行了优化,而不是针对序列化 - 这就是具有单独 DTO 的作用。否则,您的客户端将绑定到您的数据库,您的数据模型的每一次更改都有可能破坏您现有的服务客户端。

话虽如此,正确的做法是维护您映射到的单独的 DTO,这些 DTO 定义了您希望模型从外部世界看起来像的所需形状(也称为线格式)。

ServiceStack.Common包括内置映射函数(即 TranslateTo/PopulateFrom),简化了实体到 DTO 的映射,反之亦然。这是一个显示此的示例:

https://groups.google.com/d/msg/servicestack/BF-egdVm3M8/0DXLIeDoVJEJ

另一种方法是使用 [DataContract] / [DataMember] 字段来装饰要在数据模型上序列化的字段。任何不属于 [DataMember] 的属性都不会被序列化 - 因此您可以使用它来隐藏导致 StackOverflowException 的循环引用。

于 2012-02-05T17:50:55.947 回答
7

为了让我的 StackOverflowers 同胞参与这个问题,我将解释我最终做了什么:

在我描述的情况下,您必须使用标准的 .NET 序列化程序(而不是 ServiceStack 的)System.Web.Script.Serialization.JavaScriptSerializer:. 原因是您可以装饰您不希望序列化程序在属性中处理的导航[ScriptIgnore]属性。

顺便说一句,您仍然可以使用ServiceStack.JsonSerializer反序列化 - 它比 .NET 更快,并且您没有我问过这个问题的 StackOverflowException 问题。

另一个问题是如何让自我跟踪实体用[ScriptIgnore].

说明:如果没有[ScriptIgnore],序列化(使用 .NET Javascript 序列化程序)也会引发关于循环引用的异常(类似于在 ServiceStack 中引发 StackOverflowException 的问题)。我们需要消除循环性,这是使用[ScriptIgnore].

所以我编辑了ADO.NET 自跟踪实体生成器模板.TT附带的文件,并将其设置为包含在相关位置(如果有人想要代码差异,请给我写评论)。有人说编辑这些“外部”、不打算编辑的文件是一种不好的做法,但见鬼——它解决了问题,而且它是唯一不强迫我重新设计我的整体的方法应用程序(使用 POCO 代替 STE,对所有内容使用 DTO 等)[ScriptIgnore]

@mythz:我不完全同意您关于使用 DTO 的争论 - 请参阅我对您的回答的评论。我非常感谢您为构建 ServiceStack(所有模块!)并使其免费使用和开源所做的巨大努力。我只是鼓励您尊重文本序列化程序中的 [ScriptIgnore] 属性,或者提出您的属性。否则,即使实际上可以使用 DTO,他们也无法将导航属性从子对象添加回父对象,因为它们会得到 StackOverflowException。我确实将您的答案标记为“已接受”,因为毕竟它帮助我找到了解决这个问题的方法。

于 2012-02-08T20:38:22.083 回答
1

确保在序列化之前从 ObjectContext 中分离实体。

我还使用了 Newton JsonSerializer。

JsonConvert.SerializeObject(EntityObject, Formatting.Indented, new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });

于 2012-02-22T10:54:30.293 回答