c# - Web Api JSON 中丢失的 EF TPH 继承

标签 c# linq entity-framework inheritance asp.net-web-api

我已经成功设置了一些使用 TPH EF inheritance 的类, MyBaseClass , MySubClass1 , MySubClass2等等

使用 Linq 查询时 context.MyBaseClasses.Where(...) ,返回的对象都正确使用了数据库中Discriminator字段指定的子类。 (所以我最终可能会得到一个包含 MySubClass1MySubClass2 对象混合的列表。)

但是,当我通过 JSON Web Api 调用将这些对象传递给 WPF 应用程序时,接收到的对象都是 MyBaseClass ,而不是他们开始时的正确子类。

返回的对象属性类型为 public virtual List<MyBaseClass> MyThings ,所以我想它们最终都是这种类型是有道理的,但我想为每个对象保留正确的子类类型。

我如何实现这一目标?我是否需要以某种方式强制将 EF 鉴别器字段与所有其他数据一起发送?

编辑

1.

在客户端,我现在正尝试像这样反序列化 JSON(包括 $type 数据)(没有运气,项目仍然被转换回它们的基类)

HttpResponseMessage response = GetClient().GetAsync(url).Result;

if (response.IsSuccessStatusCode)
{
    string jsonMessage;
    using (Stream responseStream = response.Content.ReadAsStreamAsync().Result)
    {
        jsonMessage = new StreamReader(responseStream).ReadToEnd();
    }


    List<My.Domain.Models.MyBaseClass> thingsToReturn;

    //new method    
    thingsToReturn = JsonConvert.DeserializeObject<List<My.Domain.Models.MyBaseClass>>(jsonMessage);

    //previous method
    //thingsToReturn = response.Content.ReadAsAsync<List<My.Domain.Models.MyBaseClass>>().Result;

    return thingsToReturn;
}

2.

按照 Anish 的建议重新 SerializerSettings.TypeNameHandling ,现在我的 JSON 中出现了 $type 信息,但是这是类型 System.Data.Entity.DynamicProxies.SubClass1_5E07A4CE2F037430DC7BFA00593....客户端反序列化回 SubClass1 可以吗成功了吗?

最佳答案

这是一个序列化问题。

您可以自定义 Json.Net 的 序列化程序设置,以将类型信息包含在您的 json 对象中。

将此添加到您的HttpConfiguration:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

config 是您用来配置和初始化 Asp.Net WebApiHttpConfiguration 实例。

这将告诉 Json.Net 向每个具有类型歧义的 json 对象添加一些类型信息。这样的对象看起来像这样:

{
    "$type":"MyProjectContainingMyTypes.MySubClass1, MyProjectContainingMyTypes",
    "Name": "Tyrion Lannister",
    "DisplayName": "The Imp",
    "Traits": ["funny", "awesome", "clever"]
}
当您在 WPF 端反序列化时,

Json.Net 将知道如何处理。

这应该可以在您的 WPF 应用中使用:

var things = JsonConvert.DeserializeObject<List<MyBaseClass>>(jsonString);

然后您可以将 things 列表中的对象转换为它们各自的派生类型。

当然,您的 WPF 应用程序需要引用您定义 MyBaseClassMySubClass1 的项目。

编辑

Thanks Anish, that's almost sorted it. I can see the correct $type data in the JSON, I'm just being a dunce, and I'm not sure how to get the WebApi response as a jsonString? At the minute I'm doing response.Content.ReadAsAsync>().Result; to auto deserialize the data.

作为对您评论的回应,您可以像这样将内容读取为字符串:

var jsonString = response.Content.ReadAsStringAsync().Result;

编辑2

Anish, thanks so much for your input. As you can see, I've managed to get the JSON as a string now, but even using JsonConvert.DeserializeObject I'm still getting the same issue. Do you think it is (as I mention in Edit 2) to do with the $type being returned from the service incorrectly (as an EF proxy type)?

作为对您评论的回应,是的,您不能能够将 EF 代理类型反序列化为您想要的类型。此问题需要在 WebApi 端解决。

代理类的创建允许您延迟加载实体。代理通常用于表示引用/嵌套的实体。这允许推迟从数据库中获取引用的实体,直到需要时(如果需要的话)。

这是一个link一些关于使用 EF 加载实体的惰性急切 文档。

解决方案

您想在 WebApi Controller 操作中hydrate 对象列表并返回它,这将告诉 EF 从中加载实体数据库和类的新实例。

这里有几个选项:

选项 1

在查询中调用 ToList() 来补充集合:

var result = (from t in dbContext.Things select t).ToList();

var result = dbContext.Things.ToList();

当然,您不想返回无限制的结果集,所以添加一个范围:

var result = (from t in dbContext.Things select t).Skip(0).Take(10).ToList();

var result = dbContext.Things.Skip(0).Take(10).ToList();

请记住,使用方法时,您必须像这样显式地混合嵌套对象:

var result = dbContext
             .Things
             .Include(t => t.SomePropertyThatRepresentsSomeNestedObject) 
             .Skip(0)
             .Take(10)
             .ToList();

选项 2

为您的 DbContext 关闭延迟加载

就我个人而言,我会选择选项 1,我认为最好了解您的实体并控制您补水的时间和内容。

关于c# - Web Api JSON 中丢失的 EF TPH 继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31454712/

相关文章:

c# - 可以将新类添加到现有的 dll 并将其更新到源文件

c# - 为 Label 控件创建 KeyDown 事件处理程序

c# - 如何在 Linq FromSQL 查询中使用参数

c# - LINQ 是否可以动态添加 where 子句

c# - Entity Framework 6 重用数据注释

entity-framework - NHibernate 中的 Lazy 是什么意思

c# - 如何在 Exchange EWS 中保存 ItemAttachment 对象中附加的 EmailMessage?

c# - 无法使用“IN”列表形成正确的Linq查询

.net - NHibernate:更改授权查询

c# - 如何在短时间内调用大量http请求