You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLite按位查询返回异常结果排查(EF Core 7)

为何EF Core 7生成的SQLite查询结果偏差巨大?

问题背景

我用EF Core 7编写了如下查询:

Me.Context.Patients.Where(Function(Patient) Patient.BloodType.ReceivesFrom.HasFlag(BloodType))

生成的原生SQL为:

SELECT "p"."Id", "p"."BloodTypeId", "p"."CityId", "p"."Code", "p"."Email", "p"."FirstName", "p"."LastName", "p"."ZipCodeId", "b"."Type"
FROM "Patients" AS "p"
INNER JOIN "BloodTypes" AS "b" ON "p"."BloodTypeId" = "b"."Id"
WHERE ("b"."ReceivesFrom" & 4) = 4

查询返回结果存在严重偏差:

IdBloodTypeIdCityIdCodeEmailFirstNameLastNameZipCodeIdType
1446U6UJIoliver.runte@gmail.comAbbigailCremin124
2588LV892eunice81@gmail.comDonnellMcKenzie948
58445F6TNsusie.schaefer@gmail.comNedraStokes6664
75166LQ61eileen76@gmail.comJairoJakubowski698
1058BI56Ckristopher46@yahoo.comModestoReichert338
11594R8LP2connie_king@gmail.comRaphaelleMurphy478
165668TC6Vamber62@hotmail.comDaphneyBechtelar948
17445DM52Blucas_mraz@yahoo.comDurwardLarson674

根据血型规则,A+(枚举值4)可接受A+/-、O+/-型血捐赠,对应BloodTypeId应为2、3、4、5,测试数据中符合条件的有11条记录,但当前结果包含无效记录(如ID5的AB+型,Type为64),且遗漏了PatientId为4、6、15、19的有效记录。

相关数据

BloodTypes表数据

IdReceivesFromDonatesToType
1000
232551
332552
4152044
5152048
65124016
75124032
825519264
9255192128

Flags枚举定义

<Flags>
Public Enum BloodTypes As Byte
  <Description("?")> Unknown = 0
  <Description("O+")> OPositive = 1
  <Description("O-")> ONegative = 2
  <Description("A+")> APositive = 4
  <Description("A-")> ANegative = 8
  <Description("B+")> BPositive = 16
  <Description("B-")> BNegative = 32
  <Description("AB+")> ABPositive = 64
  <Description("AB-")> ABNegative = 128
End Enum

Patients测试数据

IdBloodTypeIdCityIdCodeEmailFirstNameLastNameZipCodeId
1446U6UJIoliver.runte@gmail.comAbbigailCremin12
2588LV892eunice81@gmail.comDonnellMcKenzie94
3685SNTB4kristi_bergnaum26@gmail.comPaigeWatsica4
42244XMHOclaire97@gmail.comGreggWilkinson26
58445F6TNsusie.schaefer@gmail.comNedraStokes66
62886C1LGbridget88@yahoo.comBriceRunolfsson55
75166LQ61eileen76@gmail.comJairoJakubowski69
861250U3Kangelina62@yahoo.comFredyHeathcote54
972DD4YBteri41@yahoo.comDorotheaLittel20
1058BI56Ckristopher46@yahoo.comModestoReichert33
11594R8LP2connie_king@gmail.comRaphaelleMurphy47
12792AALG8janice67@gmail.comWillyPouros28
13782LCH1Tdwayne_legros@yahoo.comEverardoLang6
14688HNN2patrick_gleichner78@hotmail.comKobyPurdy53
15324FWG31irene.prosacco@hotmail.comGardnerMueller27
165668TC6Vamber62@hotmail.comDaphneyBechtelar94
17445DM52Blucas_mraz@yahoo.comDurwardLarson67
187574750Klevi_lang64@yahoo.comJoelleBashirian58
19218O8Z0Qmarguerite4@yahoo.comLoyRatke98
20168UKABpaulette.moore8@hotmail.comChristaGibson48

BloodTypes表定义

CREATE TABLE "BloodTypes" (
    "Id"    INTEGER NOT NULL,
    "ReceivesFrom"  INTEGER NOT NULL DEFAULT 0,
    "DonatesTo" INTEGER NOT NULL DEFAULT 0,
    "Type"  INTEGER NOT NULL DEFAULT 0,
    CONSTRAINT "PK_BloodTypes" PRIMARY KEY("Id" AUTOINCREMENT)
);

核心原因分析

问题出在查询逻辑与需求完全倒置:

  1. 当前查询的逻辑是:筛选患者的血型能接受的捐赠类型包含A+(枚举值4),对应SQL中的("b"."ReceivesFrom" & 4) = 4,即检查患者的ReceivesFrom是否包含A+的标记。
  2. 实际需求是:筛选患者的血型属于A+能接受的捐赠类型,也就是A+可以接受O+、O-、A+、A-(对应枚举值1、2、4、8),需要检查的是A+的ReceivesFrom是否包含患者的血型Type,而非反过来。

结合BloodTypes表数据验证:

  • 符合需求的BloodTypeId2(O+,Type1)、3(O-,Type2)的ReceivesFrom是3(仅包含1、2),不包含4,因此不会被当前查询返回;
  • 无效的BloodTypeId8(AB+,Type64)的ReceivesFrom是255(包含所有枚举值),自然包含4,因此被错误返回;
  • BloodTypeId4(A+)、5(A-)的ReceivesFrom是15(包含1、2、4、8),包含4,因此被正确返回,但遗漏了O+、O-的患者。

EF Core生成的SQL位运算逻辑本身无问题,SQLite的&位运算执行正确,结果偏差完全来自业务逻辑的倒置。

修正方案

调整查询逻辑,改为检查目标血型(A+)的ReceivesFrom是否包含患者的血型Type:

' 先获取A+血型的ReceivesFrom值
Dim targetReceivesFrom = Me.Context.BloodTypes.First(Function(b) b.Type = BloodTypes.APositive).ReceivesFrom
' 筛选患者血型Type被包含在targetReceivesFrom中的记录
Dim result = Me.Context.Patients.Where(Function(p) targetReceivesFrom.HasFlag(p.BloodType.Type)).ToList()

对应的正确SQL为:

SELECT "p"."Id", "p"."BloodTypeId", "p"."CityId", "p"."Code", "p"."Email", "p"."FirstName", "p"."LastName", "p"."ZipCodeId", "b"."Type"
FROM "Patients" AS "p"
INNER JOIN "BloodTypes" AS "b" ON "p"."BloodTypeId" = "b"."Id"
WHERE (15 & "b"."Type") = "b"."Type"

(注:15是A+的ReceivesFrom值,对应枚举值1|2|4|8)

这样就能得到期望的结果:包含BloodTypeId2、3、4、5的所有患者,排除无效的AB+型患者。


内容的提问来源于stack exchange,提问作者InteXX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:22:03