将Entity Framework对象序列化用于Azure缓存

4
我们直接使用Azure Caching(而不是其中一个可用的Entity Framework包装器)。显然,对于分布式缓存,我们需要序列化对象。不幸的是,这会导致与用于导航属性的延迟加载DbContext基于代理的问题。
我看到我们可以使用自定义序列化程序来将代理映射到空集合(如果未加载)或正常对象(如果已加载),但我不确定如何实现。一种可能的实现可以基于 WCF使用的方法,但我不确定Azure是否同样适用。
理想的解决方案(这就是为什么我指向ProxyDataContractResolver)是:当发生序列化时:
  • 如果导航属性已加载,则数据将被序列化,就像它是一个普通集合一样,
  • 如果它们未加载,则不会被序列化(我希望后者在反序列化后能回到延迟加载状态,但如果不能也可以接受)。
有人以优雅的方式手动解决了这个问题吗?
提前感谢!
2个回答

2
我假设您希望缓存EF对象,那么您不需要对这些实体进行延迟加载或更改跟踪。
我认为这两个功能都是通过对象代理启用的,这将导致序列化问题(因为您不想序列化代理)。
如果禁用属性DbContext.Configuration.ProxyCreationEnabled,则实际对象而非代理的序列化应该可以正常工作。这通常在通过WCF返回POCO对象时需要,但在其他序列化场景中也可能相同。

实际上,这是我想要避免的解决方案,因为: 1)这意味着我需要修改所有查询以使其缓存不使用ProxyCreation 2)我必须编写额外的代码来包括一些前面提到的关系(这是我们***架构的问题,不幸的是我们不能使用Include方法) 3)从缓存中获取对象后启用延迟加载将是一个很好的选择。我更新了我的原始问题以显示这一点。 - tec-goblin
很抱歉没有颁发奖励 - 我不知道我会完全失去这些积分 - 我以为我可以在之后颁发这些积分。现在我没有足够的积分;). - tec-goblin

1
如果在序列化之前从DbContext中分离EF实体,则会禁用延迟加载,因此您的自定义序列化程序不会尝试序列化不属于实体图形的任何内容。
然后,当您从缓存中获取它时,如果将其附加到新的(相同的)DbContext中,则应重新启用延迟加载。
(警告:一旦您将实体与上下文分离,包含该对象的任何新查询都将创建一个新的、已连接的副本,因此您需要小心编码,以避免遇到多个潜在不同版本的同一对象运行的问题。但是,这样做应该可以让您实现想要的功能。)

我暂时不将其标记为“答案”,以防有人知道我们可以通过配置通用缓存序列化程序来实现这一点。 - tec-goblin
我认为你必须单独分离通过导航属性找到的对象 - Detach() 不会传播。如果您没有其他记录查询哪些对象的记录,则最简单的方法可能是使用 DbContext.ObjectStateManager.GetObjectStateEntries() 拉取通过上下文访问的适当类型的实体列表,然后从那里 Detach()/缓存相关实体。通过这种方式进入,您只会得到已枚举的实体,而不是直接访问它们以枚举导航属性。 - Cerebrate
这非常困难。我的Load方法几乎没有关于queryOnCacheMiss的知识。它确实知道返回的对象类型,但不知道相关的条目。ObjectStateManager中的对象可能是由于请求期间执行的另一个查询而存在,因此我需要退回到Andy的建议。 - tec-goblin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接