Castle ActiveRecord学习实践(6):延迟加载和使用Where子句

摘要:在ActiveRecord中把数据库表之间的关联关系采用对象间的聚合关系来表现,然而这却带来一系列的性能上的问题。就像我在One-Many中用到的例子Blog,使用Blog.Find(1)查找了一个Blog对象,也许我们只用到它,但事实它却把该Blog所关联的Post对象也读取出来放在了内存中,于是我们就需要有一种方法来实现只在需要Post对象的时候框架再自动读取。另外ActiveRecord只提供了Find(id),FindAll()这样两个静态的查询方法,在我们查询中还远远不够,这方面ActiveRecord为我们提供了HQL语言的支持,同时也可以通过设置Where子句来实现一些简单的查询。

 

主要内容

1.实现延迟加载

2.使用Where子句

 

一.实现延迟加载

要实现延迟加载,其实只要在HasMany特性中使用Lazy=true就可以了。来看我们的Blog类是如何声明的:

[ActiveRecord("Blogs")]

public class Blog : ActiveRecordBase

{

    
private int _id;

 

    
private String _name;

 

    
private String _author;

 

    
private IList _posts;

 

    [PrimaryKey(PrimaryKeyType.Identity, 
"blog_id")]

    
public int Id

    
{

        
get return _id; }

        
set { _id = value; }

    }


 

    [Property(
"blog_name")]

    
public String Name

    
{

        
get return _name; }

        
set { _name = value; }

    }


 

    [Property(
"blog_author")]

    
public String Author

    
{

        
get return _author; }

        
set { _author = value; }

    }


    

 

    [HasMany(
typeof(Post), Table="posts", ColumnKey="post_blogid",Lazy=true)]

    
public IList Posts

    
{

        
get return _posts; }

        
set { _posts = value; }

    }


 

    
public static void DeleteAll()

    
{

        DeleteAll( 
typeof(Blog) );

    }


 

    
public static Blog[] FindAll()

    
{

        
return (Blog[]) FindAll( typeof(Blog) );

    }


 

    
public static Blog Find(int id)

    
{

        
return (Blog) FindByPrimaryKey( typeof(Blog), id );

    }


}


可以看到唯一与我们前面声明的Blog类不同的地方就在于下面这句话:

[HasMany(typeof(Post), Table="posts", ColumnKey="post_blogid",Lazy=true)]

现在我们来写一个简单的测试代码:

[Test]

public void TestLazyLoad()

{

    
//找到Blog对象

    Blog blog 
= Blog.Find(8);

    
string resultName = blog.Name;

 

    
//执行这句话的时候才载入Post对象

    
int resultCount = blog.Posts.Count;

 

    
string expectedName = "Terrylee";

    
int expectedCount = 2;

 

    Assert.IsNotNull(blog);

    Assert.AreEqual(expectedName,resultName);

    Assert.AreEqual(expectedCount,resultCount);

}


测试,红灯!?报出了下面的错误:

ARDemo.OneManyFixture.TestLazyLoad : NHibernate.LazyInitializationException : Failed to lazily initialize a collection - no session

问题出在了我们得到Blog对象后,并没有把当前的Session保存下来,ActiveRecord在实现延迟载入时找不到一个NHibernateISession。为了保存当前的Session我们必须使用new SessionScope(),重新修改我们的测试代码之后:

[Test]

public void TestLazyLoad()

{

    
using(new SessionScope())

    
{

        
//找到Blog对象

        Blog blog 
= Blog.Find(8);

        
string resultName = blog.Name;

 

        
//执行这句话的时候才载入Post对象

        
int resultCount = blog.Posts.Count;

 

        
string expectedName = "Tech Space";

        
int expectedCount = 2;

 

        Assert.IsNotNull(blog);

        Assert.AreEqual(expectedName,resultName);

        Assert.AreEqual(expectedCount,resultCount);

    }
   

}


现在测试可以正常通过了,大家在使用延迟载入的时候不要忘了new SessionScope()

 

二.使用Where子句

ActiveRecord中实现稍微复杂的一点的查询,我们就不能用使用Find(id)FindAll()这两个静态的方法了,这时就需要使用HQL语句来实现,这个在后续文章中我会专门用一篇文章来介绍。我们也可以使用ActiveRecord来实现一些简单的查询,个人认为,这种查询把条件写在了特性里面,以一种硬编码的方式来实现,灵活性变得很差,使用的情况不是很多。看一个简单的例子,比如我们要查询某人发表的Category为“Castle”的Posts,可以在Blog实体类中添加一个CastlePosts的特性:

[HasMany(typeof(Post),Table="posts", ColumnKey="post_blogid",Where="post_categories='Castle'")]

public IList CastlePosts

{

    
get return _posts; }

    
set { _posts = value; }

}


注意:在Where中写条件时所用的Posts表的字段名,而不是Post实体类对应的属性

 

编写一个简单的测试代码:

[Test]

public void TestCondWhere()

{

    
//找到Blog对象

    Blog blog 
= Blog.Find(8);

    

    
//获取Castle的Posts数量

    
int resultCount = blog.CastlePosts.Count;

 

    
int expectedCount = 2;

 

    Assert.IsNotNull(blog);

    Assert.AreEqual(expectedCount,resultCount); 

}

 

这里我们调用CastlePosts得到的就是CategoryCastlePosts。关于延迟加载和使用Where子句就介绍到这儿了。下篇文章介绍如何在RectiveRecord中验证输入数据的有效性。

 

 

参考资料

Castle的官方网站http://www.castleproject.org

作者:TerryLee
出处:http://terrylee.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted @ 2006-04-10 18:18 TerryLee 阅读(6627) 评论(3)  编辑 收藏 所属分类: NHibernateCastle Project

  回复  引用    
#1楼 2007-01-26 21:55 | wedde [未注册用户]
请教一个问题。延迟加载的时候如何验证它是延迟加载的?
我把_posts设置为public,然后在调试状态下查看它的值,发现他已经载入了,是有值的。
就是在这句话int resultCount = blog.Posts.Count;
之前查看的。
是我理解有误还是他这个延迟加载不起作用呀?
  回复  引用    
#2楼 2007-01-26 22:08 | wedde [未注册用户]
不好意思,找到原因了,确实是延迟加载。
调试的时候当我们查看该变量的时候,系统已经自动加载了。
如果在非调试状态下,让程序停下来,然后修改数据库的记录。最后再查看的话,就会发现读取到的是修改后的值,证明是延迟加载了。
  回复  引用    
#3楼 2007-03-29 10:49 | 猫猫 [未注册用户]
问个问题,我觉得这东西确实不错,也很好用的,但唯一一点,为什么每次拿工具生成的实体类只要是带关系的就需要手动修改,请问现在有不需要修改的工具吗?
再提一下,如果很负责的关系引用可能要手动修改下就算了,但我的数据库中就两张表,就只一个一对多的关系,连这个都会搞错,也太那个什么了吧。

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  博客园首页

  新闻频道

  社区

  小组

  博问

  网摘

  闪存

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2006-08-15 08:14 编辑过
成果网帮您增加网站收入


相关链接: