db4o学习笔记(三)、db4o查询详解

  摘要:

  在本单元中详细介绍了db4o数据库的几种查询方式,对于易于初学者使用的QBE存在的弱点及db4o开发者极力推荐的NQ查询方式在不同开发语言中的实现机制、特点、示例及执行效能作了相应的阐述,同时也对NQ本身的不足进行简要的介绍,本单元中提供了大量的示例在最后给出了所有示例完整的代码。

  正文:

  db4o数据库系统提供了三种查询接口:(1)、QBE,对于初接触db4o的朋友来说,QBE是一种十分简洁的查询方式,它通过向数据库提供一个模板,系统将会返回所有成员数据非默认值的对象,在上一单元中我们简要的对QBE进行了介绍;(2)、NQ,NQ则是db4o中主要的查询接口,也是开发者所推荐的方法;(3)、SODA API,SODA是一种底层的查询接口,它提供了向后兼容的能力并且对于动态生成查询十分有用,不像NQ采用的是强类型方式。

  3.1、QBE

  当使用QBE进行查询时我们需要提供一个模板对象,数据库将会返回所有成员数据为非默认值的对象。这将通过反射所有的成员数据并生成一个由"与(AND)关系"连接所有非默认值成员数据的查询表达式来完成查询操作,下面便是在上一单元中所使用的示例:

1 None.gif [retrievePilotByName]
2 None.gifPilot proto  =   new  Pilot( " Michael Schumacher " 0 );
3 None.gifObjectSet result  =  db.Get(proto);
4 None.gifListResult(result);

  采用这种方式存在几个明细的局限性:

  (1)、db4o需要反射你提供模板对象的所有成员数据;

  (2)、不能使用高级查询表达式,如AND、OR、NOT等;

  (3)、对于数据不能使用强制条件,如int的0,string的空字串或空引用类型,因为它们在查询时都解释为非强制关系;

  (4)、需要为类提供非初始化成员数据的构造函数,这意味着在定义数据成员时不能对其进行初始化(对此笔者就曾犯过错误Sad);

  为此db4o提供了另外一种查询方式NQ。

  3.2、NQ

      使用NQ为你的查询提供了开发语言内置的支持能力(所谓NQ - 原生/本地化大概就是这个意思吧),提供类型安全机制、编译时检查及反射功能,使用面向对象的方法调用来完成查询。NQ是db4o数据库查询的主要接口也是开发者极力推荐的数据查询方式,因为NQ充分运用了开发语言的语义完整性,将会成为将来完美而安全的选择。

  3.2.1、概念

  关于NQ的概念最初来源于以下两篇文章,有兴趣的朋友可以参考一下:

  Cook/Rosenberger, Native Queries for Persistent Objects, A Design White Paper

  Cook/Rai, Safe Query Objects: Statically Typed Objects as Remotely Executable Queries

  3.2.2、原则

  NQ提供了运行于类型所有实例对象上单条或多条代码的能力,NQ查询表达式需要返回true以标记相应的对象实例为查询返回集合的一部分。如果可能的话db4o将会对NQ查询表达式进行优化并在索引的基础上执行而不是为查询提供示例对象。(此一句理解得不是很准确原文为db4o will attempt to optimize native query expressions and run them against indexes and without instantiating actual objects, where this is possible.)

  3.2.3、示例

  下面我们看看在某些开发语言中NQ是如何进行使用的。

  C# .NET 2.0

1 ExpandedBlockStart.gif ContractedBlock.gif IList  < Pilot >  pilots  =  db.Query  < Pilot >  ( delegate (Pilot pilot)  dot.gif {
2InBlock.gif    return pilot.Points == 100;
3ExpandedBlockEnd.gif}
);
  Java JDK 1.5
1 ExpandedBlockStart.gif ContractedBlock.gif List  < Pilot >  pilots  =  db.query( new  Predicate < Pilot > ()  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean match(Pilot pilot) dot.gif{
3InBlock.gif        return pilot.getPoints() == 100;
4ExpandedSubBlockEnd.gif    }

5ExpandedBlockEnd.gif}
);
  Java JDK 1.2 - 1.4
1 ExpandedBlockStart.gif ContractedBlock.gif List pilots  =  db.query( new  Predicate()  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean match(Pilot pilot) dot.gif{
3InBlock.gif        return pilot.getPoints() == 100;
4ExpandedSubBlockEnd.gif    }

5ExpandedBlockEnd.gif}
);
  C# .NET 1.1
1 None.gif IList pilots  =  db.Query( new  PilotHundredPoints());
2 None.gif
3 ExpandedBlockStart.gifContractedBlock.gif public   class  PilotHundredPoints : Predicate  dot.gif {
4ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean Match(Pilot pilot) dot.gif{
5InBlock.gif        return pilot.Points == 100;
6ExpandedSubBlockEnd.gif    }

7ExpandedBlockEnd.gif}

  从上述代码中可以看出,对于不支持泛型的语言来说,都需要提供一个扩展com.db4o.Predicate的类,并提供一个参数为待查询的类并返回布尔值的函数#.Match()或#.match(),其函数签名为:

1 None.gif bool  Match(Pilot candidate);

  使用NQ时可以充分利用现代开发环境(IDE)所提供的代码模板及自动完成功能,从而为你完成所有的代码输入功能,在VS2005中我们可以使用代码片断来创建这样的模板。

  3.2.4、高级示例

  对于复杂的查询任务,使用NQ的语法十分的精确和简捷,下面让我们看看其是如何查询指定姓名及积分范围的车手信息的对象,并与SODA查询进行简单的对比。

  SODA查询:

 1 None.gif [storePilots]
 2 None.gifdb.Set( new  Pilot( " Michael Schumacher " 100 ));
 3 None.gifdb.Set( new  Pilot( " Rubens Barrichello " 99 ));  
 4 None.gif
 5 None.gif
 6 None.gif[retrieveComplexSODA]
 7 None.gifQuery query = db.Query();
 8 None.gifquery.Constrain( typeof (Pilot));
 9 None.gifQuery pointQuery = query.Descend( " _points " );
10 None.gifquery.Descend( " _name " ).Constrain( " Rubens Barrichello " )
11 None.gif    .Or(pointQuery.Constrain( 99 ).Greater()
12 None.gif    .And(pointQuery.Constrain( 199 ).Smaller()));
13 None.gifObjectSet result = query.Execute();
14 None.gifListResult(result); 
15 None.gif

  下面是NQ进行同样查询的语法,使用NQ将会拥有上面述及的所有优点:自动完成、反射、编译时检查等等。

  C# .NET 2.0

1 ExpandedBlockStart.gif ContractedBlock.gif IList  < Pilot >  result  =  db.Query < Pilot >  ( delegate (Pilot pilot)  dot.gif {
2InBlock.gif    return pilot.Points > 99
3InBlock.gif        && pilot.Points < 199
4InBlock.gif        || pilot.Name == "Rubens Barrichello";
5ExpandedBlockEnd.gif}
);

  Java JDK 1.5
1 ExpandedBlockStart.gif ContractedBlock.gif List  < Pilot >  result  =  db.query( new  Predicate < Pilot > ()  dot.gif {
2ExpandedSubBlockStart.gifContractedSubBlock.gif    public boolean match(Pilot pilot) dot.gif{
3InBlock.gif        return pilot.getPoints() > 99
4InBlock.gif            && pilot.getPoints() < 199
5InBlock.gif            || pilot.getName().equals("Rubens Barrichello");
6ExpandedSubBlockEnd.gif   }

7ExpandedBlockEnd.gif}
);

  3.2.5、任意代码

  现在我们知道使用NQ进行查询是十分高效的,原则上可以使用任意的代码来作为查询表达式,而这也需要引起我们的注意,特别是对于那些可持久化的对象的影响。

  还是通过一个对于多数语言都有效的示例来揭示其中的具体含义吧。

 1 None.gif using  com.db4o.query;
 2 None.gif namespace  com.db4o.f1.chapter1
 3 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 4InBlock.gif    public class ArbitraryQuery : Predicate
 5ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 6InBlock.gif        private int[] _points;
 7InBlock.gif        
 8InBlock.gif        public ArbitraryQuery(int[] points)
 9ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
10InBlock.gif            _points=points;
11ExpandedSubBlockEnd.gif        }

12InBlock.gif    
13InBlock.gif        public bool Match(Pilot pilot)
14ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
15InBlock.gif            foreach (int points in _points)
16ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
17InBlock.gif                if (pilot.Points == points)
18ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
19InBlock.gif                    return true;
20ExpandedSubBlockEnd.gif                }

21ExpandedSubBlockEnd.gif            }

22InBlock.gif            return pilot.Name.StartsWith("Rubens");
23ExpandedSubBlockEnd.gif        }

24ExpandedSubBlockEnd.gif    }

25ExpandedBlockEnd.gif}

  3.2.6、NQ执行性能

  必须指出的是NQ也存在某些不足的地方:在db4o的底层总是试图将NQ查询转换为SODA,这对于所有的查询几乎是不可能完成的。对某些查询要分析其流程是十分困难的,为此db4o将不得不在持久化对象上执行真实的NQ查询,然后db4o还是会去转换部分的NQ查询表达式并使NQ查询尽可能的少。

  有关db4oNQ查询处理器的优化工作计划所涉及的方方面面,都可以通过db4o论坛提出来。

  在db4o的当前版本中,除了3.2.5所演示的以外其它示例都是经过优化后才执行的,对此我正在解决当中。

  (未完待续)以下是本单元示例的完整代码

ContractedBlock.gif ExpandedBlockStart.gif 完整的代码
  1None.gifusing com.db4o;
  2None.gifusing com.db4o.query;
  3None.gifusing com.db4o.f1;
  4None.gifnamespace com.db4o.f1.chapter1
  5ExpandedBlockStart.gifContractedBlock.gifdot.gif{
  6InBlock.gif    public class NQExample : Util
  7ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
  8InBlock.gif        public static void Main(string[] args)
  9ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 10InBlock.gif            ObjectContainer db = Db4o.OpenFile(Util.YapFileName);
 11InBlock.gif            try
 12ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 13InBlock.gif                StorePilots(db);
 14InBlock.gif                RetrieveComplexSODA(db);
 15InBlock.gif                RetrieveComplexNQ(db);
 16InBlock.gif                RetrieveArbitraryCodeNQ(db);
 17InBlock.gif                ClearDatabase(db);
 18ExpandedSubBlockEnd.gif            }

 19InBlock.gif            finally
 20ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 21InBlock.gif                db.Close();
 22ExpandedSubBlockEnd.gif            }

 23ExpandedSubBlockEnd.gif        }

 24InBlock.gif    
 25InBlock.gif        public static void StorePilots(ObjectContainer db)
 26ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 27InBlock.gif            db.Set(new Pilot("Michael Schumacher"100));
 28InBlock.gif            db.Set(new Pilot("Rubens Barrichello"99));
 29ExpandedSubBlockEnd.gif        }

 30InBlock.gif    
 31InBlock.gif        public static void RetrieveComplexSODA(ObjectContainer db)
 32ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 33InBlock.gif            Query query=db.Query();
 34InBlock.gif            query.Constrain(typeof(Pilot));
 35InBlock.gif            Query pointQuery=query.Descend("_points");
 36InBlock.gif            query.Descend("_name").Constrain("Rubens Barrichello")
 37InBlock.gif                .Or(pointQuery.Constrain(99).Greater()
 38InBlock.gif                .And(pointQuery.Constrain(199).Smaller()));
 39InBlock.gif            ObjectSet result=query.Execute();
 40InBlock.gif            ListResult(result);
 41ExpandedSubBlockEnd.gif        }

 42InBlock.gif        public static void RetrieveComplexNQ(ObjectContainer db)
 43ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 44InBlock.gif            ObjectSet result = db.Query(new ComplexQuery());
 45InBlock.gif            ListResult(result);
 46ExpandedSubBlockEnd.gif        }

 47InBlock.gif        public static void RetrieveArbitraryCodeNQ(ObjectContainer db)
 48ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 49ExpandedSubBlockStart.gifContractedSubBlock.gif            ObjectSet result = db.Query(new ArbitraryQuery(new int[]dot.gif{1,100}));
 50InBlock.gif            ListResult(result);
 51ExpandedSubBlockEnd.gif        }

 52InBlock.gif    
 53InBlock.gif        public static void ClearDatabase(ObjectContainer db)
 54ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 55InBlock.gif            ObjectSet result = db.Get(typeof(Pilot));
 56InBlock.gif            while (result.HasNext())
 57ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 58InBlock.gif                db.Delete(result.Next());
 59ExpandedSubBlockEnd.gif            }

 60ExpandedSubBlockEnd.gif        }

 61ExpandedSubBlockEnd.gif    }

 62ExpandedBlockEnd.gif}

 63None.gif 
 64None.gif
 65None.gif
 66None.gifusing com.db4o.query;
 67None.gifnamespace com.db4o.f1.chapter1
 68ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 69InBlock.gif    public class ComplexQuery : Predicate
 70ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 71InBlock.gif        public bool Match(Pilot pilot)
 72ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 73InBlock.gif            return pilot.Points > 99
 74InBlock.gif                && pilot.Points < 199
 75InBlock.gif                || pilot.Name=="Rubens Barrichello";
 76ExpandedSubBlockEnd.gif        }

 77ExpandedSubBlockEnd.gif    }

 78ExpandedBlockEnd.gif}

 79None.gif 
 80None.gif
 81None.gifusing com.db4o.query;
 82None.gifnamespace com.db4o.f1.chapter1
 83ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 84InBlock.gif    public class ArbitraryQuery : Predicate
 85ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 86InBlock.gif        private int[] _points;
 87InBlock.gif        
 88InBlock.gif        public ArbitraryQuery(int[] points)
 89ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 90InBlock.gif            _points=points;
 91ExpandedSubBlockEnd.gif        }

 92InBlock.gif    
 93InBlock.gif        public bool Match(Pilot pilot)
 94ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 95InBlock.gif            foreach (int points in _points)
 96ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 97InBlock.gif                if (pilot.Points == points)
 98ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
 99InBlock.gif                    return true;
100ExpandedSubBlockEnd.gif                }

101ExpandedSubBlockEnd.gif            }

102InBlock.gif            return pilot.Name.StartsWith("Rubens");
103ExpandedSubBlockEnd.gif        }

104ExpandedSubBlockEnd.gif    }

105ExpandedBlockEnd.gif}

转载于:https://www.cnblogs.com/JackyXu/archive/2006/11/12/558153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值