C# LINQ多表Join查询访问匿名类型报CS1061错误
问题背景
在C#项目WebsiteServices中编写LINQ多表Join关联查询代码时,触发CS1061编译错误。
出错代码
db.PointCostCentres .Join(db.CostCentres, PointCostCentre => PointCostCentre.pcc_CostCentreID, CostCentre => CostCentre.ccn_CostCentreId, (pcc, cc) => new { pcc, cc }) .Where(t => t.pcc.pcc_PointID == accountId && t.cc.ccn_Status == 'A') .Join(db.Vehicles, vc => vc.cc.ccn_CostCentreId, Vehicle => Vehicle.veh_CostCentreId, (vc, Vehicle) => new { vc, Vehicle }) .Where(veh => veh.Vehicle.veh_StatusTxt == "Active" || veh.Vehicle.veh_StatusTxt == "On Hold" || veh.Vehicle.veh_StatusTxt == "On Order") .Join(db.Vehicles, vcc => vcc.Vehicle.veh_NextFleetNo, Vehi => Vehi.veh_FleetNo, (vcc, Vehi) => new { vcc, Vehi }) .Select(v => { CostCentre = v.vc.cc.ccn_CostCentre, CostCentreName = v.vc.cc.ccn_CostCentreName, CostCentreId = v.vc.cc.ccn_CostCentreId, Colour = v.Vehicle.veh_Colour, DeliveryDate = v.Vehicle.veh_ReceivedDate, Driver = v.Vehicle.veh_Driver, FleetID = v.Vehicle.veh_FleetNo, Location = v.Vehicle.veh_Location, NVIC = v.Vehicle.veh_Nvic, Odometer = v.Vehicle.veh_LastKm, OdometerDate = v.Vehicle.veh_LastKmDate, OrderDate = v.Vehicle.veh_OrderedDate, PurchaseOrderNo = v.Vehicle.veh_PurchaseOrder, StartKM = v.Vehicle.veh_StartKm, Rego = v.Vehicle.veh_RegoNo, ReplacementRego = v.Vehicle.veh_PrevRegoNo, ReplacementFleetID = v.Vehicle.veh_PrevFleetNo, Scheme = v.Vehicle.veh_SAT, ServiceDueDate = v.Vehicle.veh_NextSvcDate, TransportBookedDate = v.Vehicle.veh_DisplTransBkd, LastServiceDate = v.Vehicle.veh_LastSvcDate, LastServiceKMs = v.Vehicle.veh_LastSvcKm, LastOdoReading = v.Vehicle.veh_LastKm, LastOdoReadingDate = v.Vehicle.veh_LastKmDate, ServiceIntervalKMs = v.Vehicle.veh_ServiceKm, ServiceIntervalMonths = v.Vehicle.veh_ServiceDays, VinNumber = v.Vehicle.veh_VinNo }) .ToList();
编译错误信息
错误 CS1061:类型为'<anonymous type: <anonymous type: <anonymous type: PointCostCentre pcc, CostCentre cc> vc, Vehicle Vehicle> vcc, Vehicle Vehi>'的匿名类型不包含'vc'的定义,且找不到可接收该类型第一个参数的名为'vc'的可访问扩展方法(是否缺少using指令或程序集引用?),所属项目为WebsiteServices。
错误原因
- 匿名类型层级访问错误:三次Join操作会生成三层嵌套的匿名类型,Select阶段的入参
v是第三次Join生成的最外层匿名对象,仅包含vcc、Vehi两个直接属性:- 第一次Join结果:匿名类型
{ pcc, cc } - 第二次Join结果:匿名类型
{ vc, Vehicle },其中vc是第一次Join的结果对象 - 第三次Join结果:匿名类型
{ vcc, Vehi },其中vcc是第二次Join的结果对象
原代码直接访问v.vc、v.Vehicle时,编译器会在最外层匿名类型上找同名属性,自然找不到,触发CS1061错误。
- 第一次Join结果:匿名类型
- 匿名类型初始化语法缺失:Select的lambda表达式中直接写属性赋值块,缺少
new关键字,会被识别为无返回值的语句lambda,本身也存在语法错误。 - 逻辑冗余问题:第三次Join关联
Vehi对象后,原代码完全没有使用该对象的属性,关联操作没有实际意义,和字段命名中ReplacementRego、ReplacementFleetID的预期逻辑不符。
修复方案
针对上述问题逐点修正:
- 调整属性访问路径,匹配匿名类型的嵌套层级:成本中心相关字段从对应嵌套层级的CostCentre对象取,主车辆相关字段从第二次Join得到的Vehicle对象取,替换车辆相关字段从第三次Join得到的Vehi对象取
- 补全Select阶段匿名类型初始化的
new关键字 - 修正替换车辆相关字段的取值来源,匹配第三次Join的业务逻辑
- (可选)重命名Join阶段的lambda参数,用语义化名称避免不同层级对象混淆
修复后的完整代码如下:
db.PointCostCentres .Join(db.CostCentres, pcc => pcc.pcc_CostCentreID, cc => cc.ccn_CostCentreId, (pcc, cc) => new { pcc, cc }) .Where(t => t.pcc.pcc_PointID == accountId && t.cc.ccn_Status == 'A') .Join(db.Vehicles, t1 => t1.cc.ccn_CostCentreId, mainVeh => mainVeh.veh_CostCentreId, (t1, mainVeh) => new { t1, mainVeh }) .Where(t2 => t2.mainVeh.veh_StatusTxt == "Active" || t2.mainVeh.veh_StatusTxt == "On Hold" || t2.mainVeh.veh_StatusTxt == "On Order") .Join(db.Vehicles, t2 => t2.mainVeh.veh_NextFleetNo, replaceVeh => replaceVeh.veh_FleetNo, (t2, replaceVeh) => new { t2, replaceVeh }) .Select(v => new { CostCentre = v.t2.t1.cc.ccn_CostCentre, CostCentreName = v.t2.t1.cc.ccn_CostCentreName, CostCentreId = v.t2.t1.cc.ccn_CostCentreId, Colour = v.t2.mainVeh.veh_Colour, DeliveryDate = v.t2.mainVeh.veh_ReceivedDate, Driver = v.t2.mainVeh.veh_Driver, FleetID = v.t2.mainVeh.veh_FleetNo, Location = v.t2.mainVeh.veh_Location, NVIC = v.t2.mainVeh.veh_Nvic, Odometer = v.t2.mainVeh.veh_LastKm, OdometerDate = v.t2.mainVeh.veh_LastKmDate, OrderDate = v.t2.mainVeh.veh_OrderedDate, PurchaseOrderNo = v.t2.mainVeh.veh_PurchaseOrder, StartKM = v.t2.mainVeh.veh_StartKm, Rego = v.t2.mainVeh.veh_RegoNo, ReplacementRego = v.replaceVeh.veh_RegoNo, ReplacementFleetID = v.replaceVeh.veh_FleetNo, Scheme = v.t2.mainVeh.veh_SAT, ServiceDueDate = v.t2.mainVeh.veh_NextSvcDate, TransportBookedDate = v.t2.mainVeh.veh_DisplTransBkd, LastServiceDate = v.t2.mainVeh.veh_LastSvcDate, LastServiceKMs = v.t2.mainVeh.veh_LastSvcKm, LastOdoReading = v.t2.mainVeh.veh_LastKm, LastOdoReadingDate = v.t2.mainVeh.veh_LastKmDate, ServiceIntervalKMs = v.t2.mainVeh.veh_ServiceKm, ServiceIntervalMonths = v.t2.mainVeh.veh_ServiceDays, VinNumber = v.t2.mainVeh.veh_VinNo }) .ToList();
优化提示:多表Join时尽量在结果选择器中平铺需要用到的字段,不要嵌套传递整个上一层的匿名对象,可以大幅降低属性访问的出错概率,也能减少EF生成SQL时的无效字段查询。
内容的提问来源于stack exchange,提问作者linkjar
相关产品推荐
相关产品推荐

