添加导航属性会破坏微风客户端映射(但不是服务器端 EF6)
Posted
技术标签:
【中文标题】添加导航属性会破坏微风客户端映射(但不是服务器端 EF6)【英文标题】:Adding Navigation property breaks breeze client-side mappings (but not Server Side EF6) 【发布时间】:2015-01-12 16:26:01 【问题描述】:我有一个独立开发的应用程序,现在正试图集成到一个更大的模型中。目前,在服务器端,有 11 个表,每个表平均有 3 个导航属性。这运行良好且稳定。
较大的模型有 55 个实体和 180 多个关系,包括我的大部分模型(在较大模型中与表的关系较少)。一旦集成,就会发生非常奇怪的事情:服务器发送相同的数据,返回相同数量的实体,但是 exportEntities 函数返回一个大约 150KB 的字符串(而不是之前返回的 1.48 MB),并且所有查询都显示一个他们之前展示的数据的十分之一。
我按照 Breeze 网站上的故障排除信息进行了操作。我查看了 Breeze 元数据,实体和关系似乎定义正确。我查看了返回的数据,十个实体中有九个没有作为对象出现,而是作为一个函数出现:function ()return e.refMap[t]
,当我展开它时,它有一个“参数”属性:Exception: TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
。
作为参考,以下是涉及重大更改的两个实体。
还款实体
public class Repayment
[Key, Column(Order = 0)]
public int DistrictId get; set;
[Key, Column(Order = 1)]
public int RepaymentId get; set;
public int ClientId get; set;
public int SeasonId get; set;
...
#region Navigation Properties
[InverseProperty("Repayments")]
[ForeignKey("DistrictId")]
public virtual District District get; set;
// The three lines below are the lines I added to break the results
// If I remove them again, the results are correct again
[InverseProperty("Repayments")]
[ForeignKey("DistrictId,ClientId")]
public virtual Client Client get; set;
[InverseProperty("Repayments")]
[ForeignKey("DistrictId,SeasonId,ClientId")]
public virtual SeasonClient SeasonClient get; set;
客户实体
public class Client : IClient
[Key, Column(Order = 0)]
public int DistrictId get; set;
[Key, Column(Order = 1)]
public int ClientId get; set;
....
// This Line lines were in the original (working) model
[InverseProperty("Client")]
public virtual ICollection<Repayment> Repayments get; set;
....
我恢复的关系只是已经存在的关系的反面,这是关于它的真正奇怪的事情之一。我确定我做错了什么,但目前我什至不确定哪些信息可能有助于调试。
对于定义外键和逆属性,我假设我必须使用数据注释或 FluentAPI,即使表遵循所有 EF 约定。有一个比另一个更好吗?是否有必要始终选择一种方法并坚持下去?上面的错误是否提供了关于我可能做错了什么的任何见解?还有其他我可以发布的信息可能会有所帮助吗?
Breeze 是一个出色的框架,它有可能真正扩大我们为东非农村小农提供援助的影响力,我很乐意让这个原型发挥作用。
谢谢
【问题讨论】:
【参考方案1】:好的,您所描述的某些内容可以通过微风的默认行为来解释,即压缩返回同一实体的多个实例的任何查询结果的负载。如果您使用默认的“json.net”程序集进行序列化,则每个实体都会发送一个额外的“$id”属性,如果再次看到相同的实体,它会通过一个简单的“$ref”属性进行序列化前面提到的“$id”的值。
在反序列化期间,在微风客户端上,这些“$refs”被解析回完整的实体。但是,因为执行反序列化的顺序可能与执行序列化的顺序不同,所以微风在内部创建延迟闭包函数(不带参数),允许延迟解析压缩结果,而不管顺序如何的序列化。这是
function ()return e.refMap[t]
你所看到的。
如果你看到这个值是实际***查询结果的一部分,那么我们有一个错误,但是如果你在调试从服务器返回的结果时看到这个值,在它们返回到调用函数之前,那么这是完全可以预料的(特别是如果您在执行之前查看闭包的内容。)
有几个问题和建议
您实际上是在处理查询结果时看到错误,还是对结果如此之小感到惊讶?如果只是大小问题,请检查您是否可以识别本应发送给客户端但丢失的数据。在您的情况下,参考压缩可能非常有效。
查看从您的网络服务返回的“原始”数据。它应该看起来像这样,带有 '$id' 和 '$ref' 属性。
[
'$id': '1',
'Name': 'James',
'BirthDate': '1983-03-08T00:00Z',
,
'$ref': '1'
]
如果是这样,请查看数据并确保存在与您的每个“$refs”相对应的“$'id”。如果不是,那么您的服务器端序列化代码有问题。如果数据看起来不像这样,那么请发回一个小例子来说明“原始”数据的样子。
【讨论】:
谢谢!这真的很有帮助。所以我在工作和非工作状态下重新运行了查询。我对数据进行分页(100 个/页),所以最后一页只有 40 个***实体。在原始数据中,我看到整个实体堆栈中每个对象实例的每个对象(或用 $ref 替换的对象)中的 $id,就像我期望循环 JSO 序列化一样。我仍在尝试格式化一些数据,但无论最终结果是否正确,看起来 $Refs 和 $ids 都是完全相同的(当我有机会进行更多解析时会详细介绍) ,但是…… ...在第一个查询(损坏的查询)中,返回到成功函数的数据缺少 90% 的实体。返回数据中存在的所有实体在原始数据中都有两位数的 id(我看到的最大 $ref 大约是 785,我没有找到,返回数据中的实体对应于大于 60 的 ref) .我怀疑堆栈中的某个实体无法被 Breeze 反序列化,并且反序列化过程被中止。我会继续挖掘,让你知道我发现了什么。对其他调查途径有何想法? 你在使用 Json.Net 吗?如果是,您是否更改了它的任何配置参数? 我相信是的。我没有对配置进行任何更改,并且正在使用由 nuget 安装的服务器上 EF6 的 Breeze Server webapi2.2 的默认 JSON 序列化器/反序列化器。同样在客户端,我没有添加脚本来序列化/反序列化 JSON。这应该都是默认的 nuget 安装。 更正:看起来 nuget 安装使用 newtonsoft.JSON。那有意义吗?我在项目中没有看到对 JSON.NET 的引用。【参考方案2】:查看您的 Gist 后,我想我明白了问题所在。您的元数据与查询返回的实际结果不同步。特别是,如果您在实际结果中查找“17”的“$id”值,您会注意到它首先在“还款”类型的“客户”属性中找到,但您的元数据没有为 'Repayment' 类型定义的 'Client' 导航属性(有一个 'ClientId' )。我的猜测是您正在重用元数据的“旧”版本。
这导致结果不完整的原因是,一旦微风确定它正在反序列化一个“实体”(即具有映射到实际实体类型的 $type 属性的 json 对象),它只会尝试反序列化“已知' 这种类型的属性,即在元数据中找到的属性。在您的情况下,“还款”类型上的“客户端”导航属性从未被反序列化,因此对那里定义的“$id”的任何引用都不可用。
【讨论】:
谢谢!现在我至少知道客户端发生了什么。我想这导致了一个问题:有没有办法追踪为什么会发生这种情况?我倾向于使用数据注释来描述关系,但也有一些 FluentApi 规范。这往往会成为一个问题吗?我可以查看服务器元数据以查看是否存在相同的问题,但如果是,我能做些什么吗?服务器元数据是由 EF 还是 Breeze 准备和提供的?关于我应该看哪里的任何想法? 一些进一步的想法(很抱歉这样轰炸你):为什么要重用旧的元数据?我没有缓存任何东西,我正在刷新连接之间的页面——当我这样做时,JS 正在更新。最后(现在)我突然想到这个元数据中有 55 个实体,而我目前只使用 11 个。这 11 个实体完全用数据注释进行了注释。其他 44 个使用数据注释和 FluentAPI 随意注释,但仅与 EF6 所需的一样多。那些其他实体中的某些东西会破坏我需要的关系吗?我应该全部注释吗? 没有更多细节(请不要看到全部 55 个)很难说。我会确保在您重新启动服务器时服务器端元数据代码实际上正在执行。如果没有,您的客户端可能正在缓存以前的元数据获取请求。 感谢您的想法。我刚刚检查了一下,服务器肯定没有缓存元数据。来自服务器的两种配置的元数据是不同的——差别不大,但在大约六个地方(为了可读性而格式化时,总共可能有 9400 行中的 100 行)。差异似乎是合理的,但我不确定我在看什么。以上是关于添加导航属性会破坏微风客户端映射(但不是服务器端 EF6)的主要内容,如果未能解决你的问题,请参考以下文章