实体框架大型查询 - 拆分为已编译的子查询?
我有一个 ASP .NET Web 表单应用程序,它收集信息以最终给出汽车保险报价的计算保费。
我有大约 10 个屏幕,我们在其中填充根 CarRisk 对象,该对象具有 CarRisk.Proposer、CarRisk.AdditionalDrivers 等属性。 CarRisk.CarRiskVehicle。
无论如何,当我进入报价摘要屏幕(总结前几页中输入的数据)时,我遇到了问题。由于每个司机都可以有索赔/定罪/医疗状况,并且每一个都与索赔类型/定罪类型等有另一种关系,因此查询非常大。
我正在设法使用 CompiledQuery 急切加载所有报价屏幕直至摘要,但是当我到达摘要时,EF 在尝试急切加载 CarRisk 时失败,因为它有 53 个包含。如果我尝试使用编译查询,该查询甚至不会编译,更不用说运行,它似乎只会导致 IIS 挂起!我感觉当我上次使用较少的包含(可能是 25)执行此操作时,我收到一个关于查询中使用了太多表的 SQL 服务器错误。我尝试将编译查询的结果合并到一个 carRisk 中,但在尝试设置类似 CarRisk.CarRiskVehicle = carRiskCarRiskVehicleCompiledQuery.CarRiskVehicle 之类的内容时出现错误,但收到错误“EntityCollection 已被初始化。InitializeRelatedCollection 方法应该只在对象图的反序列化期间被调用以初始化新的 EntityCollection。”。
因此,我恢复了延迟加载,但速度慢了很多,而且客户对性能下降感到不满意。我尝试过在 LazyLoading 时关闭 ChangeTracking,但不能说这是一个巨大的改进。
关于我应该做什么有什么建议/想法吗?
我将向您展示下面的内容,以便您可以看到
ent.CarRisks
.Include("BusinessSource") // Risk Includes
.Include("PreviousInsuranceDetail")
.Include("Quote.QuoteStatus")
.Include("ClassOfUse") // CarRisk Includes
.Include("CoverType")
.Include("ReferralSource")
.Include("MainDriver")
.Include("VoluntaryExcess")
.Include("UserSpecifiedNumberOfDrivers")
.Include("Proposer.Address") // Proposer Includes
.Include("Proposer.NumberOfOtherVehiclesAvailable")
.Include("Proposer.OwnersClub")
.Include("Proposer.BusinessCategory") // CarDriver Includes
.Include("Proposer.BusinessCategory2")
.Include("Proposer.EmploymentStatus")
.Include("Proposer.EmploymentStatus2")
.Include("Proposer.Gender")
.Include("Proposer.LicenceType")
.Include("Proposer.MaritalStatus")
.Include("Proposer.Occupation")
.Include("Proposer.Occupation2")
.Include("Proposer.Title")
.Include("Proposer.Claims.ClaimStatus")
.Include("Proposer.Claims.ClaimType")
.Include("Proposer.Convictions.ConvictionCode")
.Include("Proposer.Convictions.ConvictionTestMethod")
.Include("AdditionalDrivers.RelationshipToPolicyHolder")
.Include("AdditionalDrivers.BusinessCategory") // CarDriver Includes
.Include("AdditionalDrivers.BusinessCategory2")
.Include("AdditionalDrivers.EmploymentStatus")
.Include("AdditionalDrivers.EmploymentStatus2")
.Include("AdditionalDrivers.Gender")
.Include("AdditionalDrivers.LicenceType")
.Include("AdditionalDrivers.MaritalStatus")
.Include("AdditionalDrivers.Occupation")
.Include("AdditionalDrivers.Occupation2")
.Include("AdditionalDrivers.Title")
.Include("AdditionalDrivers.Claims.ClaimStatus")
.Include("AdditionalDrivers.Claims.ClaimType")
.Include("AdditionalDrivers.Convictions.ConvictionCode")
.Include("AdditionalDrivers.Convictions.ConvictionTestMethod")
.Include("CarRiskVehicle.Car")
.Include("CarRiskVehicle.OvernightParkLocation")
.Include("CarRiskVehicle.RegisteredKeeper")
.Include("CarRiskVehicle.RegisteredOwner")
.Include("CarRiskVehicle.Transmission")
.Include("CarRiskVehicle.Modifications")
.Include("CarRiskVehicle.CarRiskVehicleSecurityDevices")
.Include("CarRiskVehicle.MotorHomeType")
.Include("CarRiskVehicle.AlarmType")
.Include("CarRiskVehicle.TrackerType")
.Include("CarRiskVehicle.Address")
I've got an ASP .NET web forms application that collects information to eventually give a calculated premium for a car insurance quote.
I've got about 10 screens in which we populate our root CarRisk object, this has properties such as CarRisk.Proposer, CarRisk.AdditionalDrivers & CarRisk.CarRiskVehicle.
Anyway, I've got a problem when I get to the quote summary screen (summarises the data entered in the previous pages). As each driver can have claims/convictions/medical conditions and each of these has another relationship to claimType/convictionType etc the query is very large.
I'm managing to eager load all the quote screens up to summary using CompiledQuery but when I get to the summary EF fails when trying to eager load the CarRisk as it has 53 Includes. If I try to use compiled query, the query won't even compile let alone run, it just seems to cause IIS to hang! I get the feeling that when I last did this with less includes (maybe 25) I get a SQL server error about too many tables being used in the query. I've tried combining the results of the compiled queries into one carRisk but I get an error when trying to set something like CarRisk.CarRiskVehicle = carRiskCarRiskVehicleCompiledQuery.CarRiskVehicle but I get the error "The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph.".
So I've reverted to lazy loading but it's alot slower and the client's unhappy about the performance hit. I've tried turning off ChangeTracking whilst LazyLoading but can't say it's a massive improvement.
Any suggestions/ideas on what I should do?
I'll show you the includes below so you can see
ent.CarRisks
.Include("BusinessSource") // Risk Includes
.Include("PreviousInsuranceDetail")
.Include("Quote.QuoteStatus")
.Include("ClassOfUse") // CarRisk Includes
.Include("CoverType")
.Include("ReferralSource")
.Include("MainDriver")
.Include("VoluntaryExcess")
.Include("UserSpecifiedNumberOfDrivers")
.Include("Proposer.Address") // Proposer Includes
.Include("Proposer.NumberOfOtherVehiclesAvailable")
.Include("Proposer.OwnersClub")
.Include("Proposer.BusinessCategory") // CarDriver Includes
.Include("Proposer.BusinessCategory2")
.Include("Proposer.EmploymentStatus")
.Include("Proposer.EmploymentStatus2")
.Include("Proposer.Gender")
.Include("Proposer.LicenceType")
.Include("Proposer.MaritalStatus")
.Include("Proposer.Occupation")
.Include("Proposer.Occupation2")
.Include("Proposer.Title")
.Include("Proposer.Claims.ClaimStatus")
.Include("Proposer.Claims.ClaimType")
.Include("Proposer.Convictions.ConvictionCode")
.Include("Proposer.Convictions.ConvictionTestMethod")
.Include("AdditionalDrivers.RelationshipToPolicyHolder")
.Include("AdditionalDrivers.BusinessCategory") // CarDriver Includes
.Include("AdditionalDrivers.BusinessCategory2")
.Include("AdditionalDrivers.EmploymentStatus")
.Include("AdditionalDrivers.EmploymentStatus2")
.Include("AdditionalDrivers.Gender")
.Include("AdditionalDrivers.LicenceType")
.Include("AdditionalDrivers.MaritalStatus")
.Include("AdditionalDrivers.Occupation")
.Include("AdditionalDrivers.Occupation2")
.Include("AdditionalDrivers.Title")
.Include("AdditionalDrivers.Claims.ClaimStatus")
.Include("AdditionalDrivers.Claims.ClaimType")
.Include("AdditionalDrivers.Convictions.ConvictionCode")
.Include("AdditionalDrivers.Convictions.ConvictionTestMethod")
.Include("CarRiskVehicle.Car")
.Include("CarRiskVehicle.OvernightParkLocation")
.Include("CarRiskVehicle.RegisteredKeeper")
.Include("CarRiskVehicle.RegisteredOwner")
.Include("CarRiskVehicle.Transmission")
.Include("CarRiskVehicle.Modifications")
.Include("CarRiskVehicle.CarRiskVehicleSecurityDevices")
.Include("CarRiskVehicle.MotorHomeType")
.Include("CarRiskVehicle.AlarmType")
.Include("CarRiskVehicle.TrackerType")
.Include("CarRiskVehicle.Address")
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是疯了!!!肯定要回到应用架构上再思考一下。相信我:您不需要在单个查询中包含所有这些内容。划分查询或使用投影。
如果您的实体被代理进行延迟加载 (POCO) 或者它可能是从
EntityObject
派生的,则会发生您遇到的错误。在加载这些实体之前尝试关闭延迟加载 (objectContext.ContextOptions
)。This is insane!!! Definitely return to application architecture and think again. Believe me: you don't need all these includes in single query. Divide the query or use projections.
The error you got happens if your entity is proxied for lazy loading (POCO) or if perhaps it is derived from
EntityObject
. Try to turn off lazy loading (objectContext.ContextOptions
) before you load these entities.