之前分析过Select和Delete的普通处理模式和批处理模式,这次继续按照ORM_Adv_Tutorial 示例中的指引来分析。
4.Gateway.BeginBatchGateway(n)
正常来说,在调用普通Gateway.BatchUpdate()与Gateway.BeginBatchGateway(1).BatchUpdate()的运行时逻辑应该是一致的,但结果出乎意料:
Gateway.BatchUpdate():
Batch
Update
all
LocalUsers
'
Birthday as null.
Text SELECT [ID],[Name],[Status],[Birthday],[LoginName],[Password] FROM [vLocalUser
Text SELECT [ID],[ProfileContent],[UserID] FROM [UserProfile] WHERE [UserID] = @ID
Parameters:
@ID[Guid] = 6018b930-4d5f-48be-acad-610f6ebf822c
Text SELECT [ID],[Description],[Number],[UserID] FROM [LocalUserPhone] WHERE [UserID] = @ID
Parameters:
@ID[Guid] = 6018b930-4d5f-48be-acad-610f6ebf822c
Text UPDATE [User] SET [Birthday] = null WHERE [ID] =
'
6018b930
-
4d5f
-
48be
-
acad
-
610f6ebf822c
'
;
Gateway.BeginBatchGateway(1).BatchUpdate():
Batch
Update
all
LocalUsers
'
Birthday as Now.
Text SELECT [ID],[Name],[Status],[Birthday],[LoginName],[Password] FROM [vLocalUser
Text SELECT [ID],[ProfileContent],[UserID] FROM [UserProfile] WHERE [UserID] = @ID
Parameters:
@ID[Guid] = 6018b930-4d5f-48be-acad-610f6ebf822c
Text UPDATE [User] SET [Birthday] =
'
2006
-
11
-
11
13
:
06
:
30
'
WHERE [ID] =
'
6018b930
-
4d5f
-
48be
-
acad
-
610f6ebf822c
'
;
Text SELECT [ID],[Description],[Number],[UserID] FROM [LocalUserPhone] WHERE [UserID] = @ID
Parameters:
@ID[Guid] = 6018b930-4d5f-48be-acad-610f6ebf822c
从上面可以发现,Gateway.BeginBatchGateway(1).BatchUpdate()是先Update了,再Select(因为UserPhone设置了LazyLoad=false),按照一般来说,正确的应该是先Select,再Update的,就如Gateway.BatchUpdate()的运行时逻辑。为了再详细弄明白,测试了Gateway.BeginBatchGateway(3),Gateway.BeginBatchGateway(10),Gateway.BeginBatchGateway(100),每次总是先进行 n-1 次Select,接着就进行 Update n条记录,再进行一次 Select ;不知道这是不是Bug,因为这过程的先后次序不正常。
(经 Teddy 的确认“次序可能是有点不对”。)
PS:在V3.20更新中已修复此Bug
5.删除
这里就不分是否Batch了,直接看运行时逻辑。这里删除所有LocalUser记录(表中只有两个记录):
Batch
Delete
all
LocalUsers whose Birthday
is
null
.
Text
SELECT
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
WHERE
[
Birthday
]
IS
NULL
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
6143c84e
-
cc6f
-
4231
-
bbf8
-
498266b7f29b
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
a01d90e1
-
2e96
-
4c11
-
8d76
-
cd71c9247ff0
Text
SELECT
[
ID
]
,
[
Description
]
,
[
Number
]
,
[
UserID
]
FROM
[
LocalUserPhone
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
6143c84e
-
cc6f
-
4231
-
bbf8
-
498266b7f29b
Text
DELETE
FROM
[
UserProfile
]
WHERE
[
ID
]
=
'
b693ad49-90c8-4f79-b9ff-bbb1a14228bb
'
;
DELETE
FROM
[
User
]
WHERE
[
ID
]
=
'
6143c84e-cc6f-4231-bbf8-498266b7f29b
'
;
DELETE
FROM
[
LocalUser
]
WHERE
[
ID
]
=
'
6143c84e-cc6f-4231-bbf8-498266b7f29b
'
;
Text
SELECT
[
ID
]
,
[
Description
]
,
[
Number
]
,
[
UserID
]
FROM
[
LocalUserPhone
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
a01d90e1
-
2e96
-
4c11
-
8d76
-
cd71c9247ff0
Text
DELETE
FROM
[
UserProfile
]
WHERE
[
ID
]
=
'
943a80e5-2ad4-4de3-9ac8-d38278775472
'
;
DELETE
FROM
[
User
]
WHERE
[
ID
]
=
'
a01d90e1-2e96-4c11-8d76-cd71c9247ff0
'
;
DELETE
FROM
[
LocalUser
]
WHERE
[
ID
]
=
'
a01d90e1-2e96-4c11-8d76-cd71c9247ff0
'
;
可见,逻辑过程正确,先查询到全部的LocalUser(通过视图vLocalUser),然后获取每个LocalUser的UserProfile,接着是删除操作中需要用到UserPhone,则查询每个LocalUser的UserPhones;接着就是将LocalUser所有关联的实体都删除掉,最后才删除LocalUser。
你会看到一个问题:怎么不删除UserPhones的呢?因为UserPhones是空的。那这又是为什么呢?这追根到Save()代码段:
1
//
user.Phones[0].Description = "modified phone desc for home";
2
//
user.Phones[1].Description = "modified phone desc for work";
3
4
//
now, because the user is saved before, most real operations are update, insert or update are all transparent to us. we can always easily SAVE them.
5
//
see runtime log for details and compare to those with the first time save.
6
WriteLine(
string
.Empty);
7
WriteLine(
"
Second Time Save:
"
);
8
WriteLine(
string
.Empty);
9
gateway.Save
<
LocalUser
>
(user);
我们将1、2行注释掉,然后再重复上面的操作过程,结果中出现了Delete UserPhone:
Text
DELETE
FROM
[
UserProfile
]
WHERE
[
ID
]
=
'
8dd8e54c-eacc-402e-85db-2ce16823bc50
'
;
DELETE
FROM
[
LocalUserPhone
]
WHERE
[
ID
]
=
'
1fe310e9-eff0-4138-9216-81a1d8f36bf6
'
;
DELETE
FROM
[
LocalUserPhone
]
WHERE
[
ID
]
=
'
2fa74a7c-788f-48a2-bfbe-8bd01609434c
'
;
DELETE
FROM
[
User
]
WHERE
[
ID
]
=
'
20f1265a-f58f-4283-bc80-a2fd02add340
'
;
DELETE
FROM
[
LocalUser
]
WHERE
[
ID
]
=
'
20f1265a-f58f-4283-bc80-a2fd02add340
'
;
为什么这样的呢?回顾 ORM_Adv_Tutorial 示例的分析与学习(1) 中对Save()操作后的分析“更新UserPhone为什么要先删除原先的UserPhone呢?”,错误就发生在这里了,暂时还没想到什么办法来处理这个错误。(不会又是Bug吧?)PS:在V3.2.1的更新中已经修改此Bug.
6.FindArray()
WriteLine(
"
Find all saved local users order by Status descendent:
"
);
WriteLine(
string
.Empty);
LocalUser[] users
=
gateway.FindArray
<
LocalUser
>
(WhereClip.All, LocalUser._.Status.Desc);
很奇怪的现象发生了,如果只有一条记录时,返回数组中的第一项应该是Find()的结果相同(可以查看
ORM_Adv_Tutorial 示例的分析与学习(1)
中Find()的结果)。但是
这里是FindArray<LocalUser>(),LocalUser定义了UserPhones:
Find
all
saved local users
order
by
Status descendent:
Text
SELECT
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
ORDER
BY
[
Status
]
DESC
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
The found local users:
Text
SELECT
[
ID
]
,
[
Name
]
,
[
ParentID
]
FROM
[
v_Group_UserGroup
]
WHERE
[
UserGroup_UserID
]
=
@UserGroup_UserID_11b60f92f7f3467f9e3ab3b3556533e8
ORDER
BY
[
Name
]
DESC
Parameters:
@UserGroup_UserID_11b60f92f7f3467f9e3ab3b3556533e8
[
Guid
]
=
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
Text
SELECT
[
ID
]
,
[
Description
]
,
[
Number
]
,
[
UserID
]
FROM
[
LocalUserPhone
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
<
?xml version
=
"
1.0
" encoding
=
"utf
-
16
"?
>
<
ArrayOfLocalUser xmlns:xsi
=
"http:
//
www.w3.org
/
2001
/
XMLSchema
-
instance" xmlns:xsd
=
"http:
//
www.w3.org
/
2001
/
XMLSchema"
>
<
LocalUser
>
<
ID
>
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
</
ID
>
<
Name
>
<
FirstName
>
teddy
</
FirstName
>
<
LastName
>
ma
</
LastName
>
</
Name
>
<
Profile
>
<
ID
>
63020ae8
-
fb91
-
4891
-
98e4
-
d6cedab257f4
</
ID
>
<
ProfileContent
>some
sample content
</
ProfileContent
>
<
UserID
>
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
</
UserID
>
</
Profile
>
<
Groups
/>
<
Status
>
Available
</
Status
>
<
Birthday xsi:nil
=
"true"
/>
<
Phones
>
<
LocalUserPhone
>
<
ID
>
4a9ee1c2
-
2d44
-
4879
-
a2af
-
184194d7fb3d
</
ID
>
<
Description
>
home
</
Description
>
<
Number
>
111
</
Number
>
<
UserID
>
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
</
UserID
>
</
LocalUserPhone
>
<
LocalUserPhone
>
<
ID
>
f8571439
-
19a3
-
4c85
-
9dee
-
c6a598d50a25
</
ID
>
<
Description
>
work
</
Description
>
<
Number
>
222
</
Number
>
<
UserID
>
48719a11
-
61a3
-
4e29
-
ad86
-
41cd93775684
</
UserID
>
</
LocalUserPhone
>
</
Phones
>
</
LocalUser
>
</
ArrayOfLocalUser
>
按理来说,正确的应该是包含UserPhones的。
暂时将这个问题放下,
开始来看看FindArray()的运行时逻辑过程:
Find
all
saved local users
order
by
Status descendent:
Text
SELECT
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
ORDER
BY
[
Status
]
DESC
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
ffacb2d2
-
99bc
-
4fe6
-
ae50
-
92d77a839de9
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
430530ab
-
9ed4
-
453e
-
8e30
-
e6c9335ea83c
这是只有两条记录的情况,可见,除了LocalUser外,只会对设置了LazyLoad=false的属性(这里是UserProfile)项进行查询。
来计算一下一个进行了多少次查询:S=1+N×1=N+1,这里只是1对1的关系
如果一共有10万条记录,再需要100001次查询,但一般的查询并不需要一次性返回全部的记录。
如果是1对M的关系,则S=1+N×M,将是几何倍数增长。
所以还是尽避免设置LazyLoad=false的都尽量避免,特别是1对多的关系。
7.Gateway.GetPageSelector()和PageSelector.FindPage()
方法:GetPageSelector<EntityType>(WhereClip where, OrderByClip orderBy, int pageSize)
返回PageSelector对象。
PageSelector的FinePage(int pageNo)返回EntityType[]。
示例代码:分页大小2,第1页
LocalUser[] users
=
gateway.GetPageSelector
<
LocalUser
>
(LocalUser._.Status
==
UserStatus.Available
&
LocalUser._.Birthday
==
null
, OrderByClip.Default,
2
).FindPage(
1
);
使用了"&"来连接两个查询条件;
运行逻辑过程:
Text
SELECT
TOP
2
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
WHERE
(
[
Status
]
=
@Status_2cd18d6e925143cd8147109ec45b5ce0
)
AND
(
[
Birthday
]
IS
NULL
)
Parameters:
@Status_2cd18d6e925143cd8147109ec45b5ce0
[
Int32
]
=
Available
Text
SELECT
TOP
2
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
WHERE
(
[
Status
]
=
@Status_2cd18d6e925143cd8147109ec45b5ce0
)
AND
(
[
Birthday
]
IS
NULL
)
Parameters:
@Status_2cd18d6e925143cd8147109ec45b5ce0
[
Int32
]
=
Available
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
cd447df2
-
e5a1
-
40ae
-
b089
-
694d99661629
Text
SELECT
[
ID
]
,
[
ProfileContent
]
,
[
UserID
]
FROM
[
UserProfile
]
WHERE
[
UserID
]
=
@ID
Parameters:
@ID
[
Guid
]
=
9f73649a
-
83fc
-
4b2c
-
8d90
-
b78e89c63942
这里又有一个奇怪的现象,就是进行了两次同样的Select查询。
PS:在V3.2.0的更新中已经修改此Bug.
示例代码:分页大小2,第2页
users
=
gateway.GetPageSelector
<
LocalUser
>
(WhereClip.All, OrderByClip.Default,
2
).FindPage(
2
);
运行时逻辑:
Text
SELECT
TOP
2
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
WHERE
(
[
ID
]
NOT
IN
(
SELECT
TOP
2
[
ID
]
FROM
[
vLocalUser
]
) )
Text
SELECT
TOP
2
[
ID
]
,
[
Name
]
,
[
Status
]
,
[
Birthday
]
,
[
LoginName
]
,
[
Password
]
FROM
[
vLocalUser
]
WHERE
(
[
ID
]
NOT
IN
(
SELECT
TOP
2
[
ID
]
FROM
[
vLocalUser
]
) )
问题依旧``````重复的两次Select查询。
PS:在V3.20更新中已修复此Bug
8.聚会查询
示例代码:
//
aggregation queries are all similar, so here demos count only
int
userCount
=
gateway.Count
<
User
>
(WhereClip.All, PropertyItem.All,
false
);
WriteLine(
"
User Count:
"
+
userCount.ToString());
userCount
=
gateway.Count
<
User
>
(WhereClip.All, LocalUser._.Status,
true
);
WriteLine(
"
User Count by DISTINCK Status:
"
+
userCount.ToString());
运行时逻辑:
Text
select
COUNT
(
*
)
from
[
User
]
User
Count
:
9
Text
select
COUNT
(
DISTINCT
[
Status
]
)
from
[
User
]
User
Count
by
DISTINCK Status:
1
这算是最简洁的SQL语句了,意思已非常明确地显示在代码之中。
9.Exists()
有两个重载版本,一个可以指定WhereClip,一个是主键PK Values。
示例中的代码:
WriteLine(
"
Whether the saved local user exists:
"
);
WriteLine(
string
.Empty);
bool
isFound
=
gateway.Exists
<
LocalUser
>
(localUser.ID);
WriteLine(
"
Is existed?:
"
);
WriteLine(isFound.ToString());
运行时逻辑:
Whether the saved local
user
exists
:
Text
SELECT
[
ID
]
FROM
[
vLocalUser
]
WHERE
[
ID
]
=
@ID_6bbb443a8a9b4ef999a3ac0adfd5e0ef
Parameters:
@ID_6bbb443a8a9b4ef999a3ac0adfd5e0ef
[
Guid
]
=
3315ed3d
-
54dd
-
416c
-
972f
-
787f8018a522
Is
existed?:
True
10.FindScalar()和FindSinglePropertyArray()
示例代码:
UserStatus status
=
(UserStatus)gateway.FindScalar
<
LocalUser
>
(LocalUser._.ID
==
localUser.ID, OrderByClip.Default, LocalUser._.Status);
WriteLine(
"
The found user's status:
"
);
WriteLine(status.ToString());
运行时逻辑:
Text
SELECT
[
Status
]
FROM
[
vLocalUser
]
WHERE
[
ID
]
=
@ID_5b5e95699b604b2c97433eb87d892122
Parameters:
@ID_5b5e95699b604b2c97433eb87d892122
[
Guid
]
=
52d3e8fc
-
c34c
-
470d
-
bbf9
-
c43da2432ef7
The found
user
'
s status:
Available
示例代码:
WriteLine(
"
Find all saved local users's single property ID's array order by Status descendent:
"
);
WriteLine(
string
.Empty);
object
[] ids
=
gateway.FindSinglePropertyArray
<
LocalUser
>
(WhereClip.All, LocalUser._.Status.Desc, LocalUser._.ID);
WriteLine(
"
The found local users's ID:
"
);
WriteLine(
string
.Empty);
foreach
(Guid id
in
ids)
{
WriteLine(id.ToString());
}
运行时逻辑:
Find
all
saved local users
'
s single property ID
'
s array
order
by
Status descendent:
Text
SELECT
[
ID
]
FROM
[
vLocalUser
]
ORDER
BY
[
Status
]
DESC
The found local users
'
s ID:
4c19952f-1532-4402-9ed7-3adcb5b6e5b8
7bca5426-5d16-4360-b2e0-86fa086e477f
7~10的代码和运行时逻辑输出都很明显地解释了实现的功能。
好了,暂时就分析到这里,等以Access作数据库的分析后,再添加进来作对比。