ORM_Adv_Tutorial 示例的分析与学习(2)

之前分析过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作数据库的分析后,再添加进来作对比。

你可能感兴趣的:(orm)