我已经成功设置了一些使用 TPH EF inheritance 的类, MyBaseClass
, MySubClass1
, MySubClass2
等等
使用 Linq 查询时 context.MyBaseClasses.Where(...)
,返回的对象都正确使用了数据库中Discriminator字段指定的子类。 (所以我最终可能会得到一个包含 MySubClass1
或 MySubClass2
对象混合的列表。)
但是,当我通过 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 WebApi 的 HttpConfiguration
实例。
这将告诉 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 应用程序需要引用您定义 MyBaseClass
和 MySubClass1
的项目。
编辑
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/