这是我的查询(EF Core 7 和生成的原始 SQL):
Me.Context.Patients.Where(Function(Patient) Patient.BloodType.ReceivesFrom.HasFlag(BloodType))
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
...结果如下:
-------------------------------------------------------------------------------------------------------------
| Id | BloodTypeId | CityId | Code | Email | FirstName | LastName | ZipCodeId | Type |
-------------------------------------------------------------------------------------------------------------
| 1 | 4 | 46 | U6UJI | [email protected] | Abbigail | Cremin | 12 | 4 |
| 2 | 5 | 88 | LV892 | [email protected] | Donnell | McKenzie | 94 | 8 |
| 5 | 8 | 44 | 5F6TN | [email protected] | Nedra | Stokes | 66 | 64 |
| 7 | 5 | 16 | 6LQ61 | [email protected] | Jairo | Jakubowski | 69 | 8 |
| 10 | 5 | 8 | BI56C | [email protected] | Modesto | Reichert | 33 | 8 |
| 11 | 5 | 94 | R8LP2 | [email protected] | Raphaelle | Murphy | 47 | 8 |
| 16 | 5 | 66 | 8TC6V | [email protected] | Daphney | Bechtelar | 94 | 8 |
| 17 | 4 | 45 | DM52B | [email protected] | Durward | Larson | 67 | 4 |
-------------------------------------------------------------------------------------------------------------
问题是查询结果非常不准确。
这是
BloodTypes
数据:
----------------------------------------
| Id | ReceivesFrom | DonatesTo | Type |
----------------------------------------
| 1 | 0 | 0 | 0 |
| 2 | 3 | 255 | 1 |
| 3 | 3 | 255 | 2 |
| 4 | 15 | 204 | 4 |
| 5 | 15 | 204 | 8 |
| 6 | 51 | 240 | 16 |
| 7 | 51 | 240 | 32 |
| 8 | 255 | 192 | 64 |
| 9 | 255 | 192 | 128 |
----------------------------------------
支持枚举:
<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
数据(假的,用 Bogus 创建):
-----------------------------------------------------------------------------------------------------------
| Id | BloodTypeId| CityId | Code | Email | FirstName | LastName | ZipCodeId |
-----------------------------------------------------------------------------------------------------------
| 1 | 4 | 46 | U6UJI | [email protected] | Abbigail | Cremin | 12 |
| 2 | 5 | 88 | LV892 | [email protected] | Donnell | McKenzie | 94 |
| 3 | 6 | 85 | SNTB4 | [email protected] | Paige | Watsica | 4 |
| 4 | 2 | 24 | 4XMHO | [email protected] | Gregg | Wilkinson | 26 |
| 5 | 8 | 44 | 5F6TN | [email protected] | Nedra | Stokes | 66 |
| 6 | 2 | 88 | 6C1LG | [email protected] | Brice | Runolfsson | 55 |
| 7 | 5 | 16 | 6LQ61 | [email protected] | Jairo | Jakubowski | 69 |
| 8 | 6 | 12 | 50U3K | [email protected] | Fredy | Heathcote | 54 |
| 9 | 7 | 2 | DD4YB | [email protected] | Dorothea | Littel | 20 |
| 10 | 5 | 8 | BI56C | [email protected] | Modesto | Reichert | 33 |
| 11 | 5 | 94 | R8LP2 | [email protected] | Raphaelle | Murphy | 47 |
| 12 | 7 | 92 | AALG8 | [email protected] | Willy | Pouros | 28 |
| 13 | 7 | 82 | LCH1T | [email protected] | Everardo | Lang | 6 |
| 14 | 6 | 8 | 8HNN2 | [email protected] | Koby | Purdy | 53 |
| 15 | 3 | 24 | FWG31 | [email protected] | Gardner | Mueller | 27 |
| 16 | 5 | 66 | 8TC6V | [email protected] | Daphney | Bechtelar | 94 |
| 17 | 4 | 45 | DM52B | [email protected] | Durward | Larson | 67 |
| 18 | 7 | 57 | 4750K | [email protected] | Joelle | Bashirian | 58 |
| 19 | 2 | 18 | O8Z0Q | [email protected] | Loy | Ratke | 98 |
| 20 | 1 | 6 | 8UKAB | [email protected] | Christa | Gibson | 48 |
-----------------------------------------------------------------------------------------------------------
看到问题了吗?
A+
血液(4
枚举中的BloodTypes
标志)可以从类型A+/-
和O+/-
(来源:Red Cross)接收,因此查询应该返回恰好 11 行,其 BloodTypeId
是 2
、3
、4
或 5
。 (我已确保我的 Patients
测试数据中存在满足此要求的 11 个随机行。)
Flag
4
(A+
) 的 ReceivesFrom
值为 15,它是 1
、2
、4
和 8
(O+
、O-
、) 类型的总和A+
和 A-
)。
这是我的
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)
);
令人沮丧的是查询结果包含无效行并省略有效行。例如,检查结果中的
ID#5
:64
(AB+
) 不可能适合 15
。这在数学上是不可能的。
PatientId
、4
、6
、15
和19
在哪里?为什么他们被省略了?他们在A+
可接受的血型范围内。
这是怎么回事?为什么 SQLite 会产生如此不准确的结果?
事实证明查询行为正确。我的期望是不正确的。我倒着看问题180°。
我们不应该试图将
AB+
(64) 塞进 A+.ReceivesFrom
聚合 (15) 中(这显然行不通),我们应该走另一条路,将 A+
(4) 放入 AB+.ReceivesFrom
聚合中( 255).
当我们分解它时,这是完全有道理的。
规则:我们希望所有可以从
A+
接受治疗的患者。简单。
根据
图表,这是
A
和AB
。这两个的 ReceivesFrom
总数分别为 15 和 255。 A+
(4) 适合这两者,因此查询返回所有 A/AB
血型。
问题解决了。事实上,这从来都不是问题。