掷鸡蛋者
发表于: 2010/5/25 9:22 引用 回复 只看该作者 1# TOP
管理员
性别: 男
积分:52151
阅读权限:43363
帖子: 8307
加入时间: 2010/4/29
最后登录: 2017/12/14

下面就可能被关心的问题逐一说明。本文会经常更新,不断补充。

本文的最新版,请访问此处http://www.wojilu.com/common/page/94 


0、我记录ORM有什么优点?

1)同时支持多种数据库;
2)速度快:内置透明缓存机制,只要内存足够,大多数时候,速度超过原生的sql查询;
3)使用简单;
4)面向对象的思维模式;
5)另外还有:简单方便的sql直接运行机制。


1、是不是目前只能使用 Int 类型的主键,无法使用 GUID 主键?
[答] 是的。而且你在领域模型中不用另外定义 Id ,因为你继承的基类 ObjectBase 已经自带了 Id。虽然 GUID 在数据迁移等场合更加方便,但这个框架更多的考虑到 url 等的友好性,所以暂不支持。争取将来支持。如果实在要使用,可以参看此处的做法:http://www.wojilu.com/tag/guid 

2、虽然框架可以根据领域模型自动建表,但如果修改了模型,还可以同步到数据表中吗?
[答] 很遗憾,目前不可以,还没有找到非常完善又简单的解决方案。你需要手动打开数据表更新字段信息。

3、这个 ORM 支持多个数据库吗?
[答] 支持。而且配置很简单。先看一下配置的截图:



4、这个 ORM 支持哪几种数据库?
[答] 目前支持sqlserver/access/mysql,将来会支持更多数据库。

如何使用sqlserver数据库?参看:http://www.wojilu.com/Forum1/Topic/67 
如何使用mysql数据库?参看:http://www.wojilu.com/common/page/77 

可以使用sqlserver express吗?可以。参看:http://www.wojilu.com/Forum1/Post/2109 

5、支持存储过程吗?
[答] 不支持。这是ORM的特点,或者说,ORM的目的就是丢弃存储过程。这个思路可能需要慢慢接受。主要原因,在于如果使用存储过程,往往意味着把业务逻辑浓缩进存储过程中;这和以领域模型为中心的思路有悖。

更多说明参看:http://www.wojilu.com/Forum1/Topic/358 


6、能就常用的查询用法举些例子吗?

[答]例子如下(注意,下面例子中的select方法不建议使用,因为对缓存不利):

根据Id查询
TMember member = TMember.findById( 8 );

参数化查询1
List<Article> articles = TArticle.find( "Title=:t" ).set( "t", art.Title ).list();

参数化查询2
List<TCat> cats = TCat.find( "Id>:myid" ).set( "myid", 5 ).select( "Id,Name,ArticleCount" ).list();


参数化查询3(id in 的特殊处理)

List<TCat> cats = TCat.find( "Id in (:id1,:id2,:id3)" )

                .set( "id1", 6 )

                .set( "id2", 7 )

                .set( "id8", 8 )

                .list();——这句是对的。或者拼接ids,不使用参数化

注意,不应该是List<TCat> cats = TCat.find( "Id in (:ids)" )

                .set( "ids", "6,7,8" )

                .list();——这句是错误的

更多说明在这里:http://www.wojilu.com/Forum1/Topic/1108


参数化查询4(like语句中的特殊处理)

正确的做法是:Post.find("Status=0 and Title like '%'+:t+'%'").set("t",t).list()

注意:不是 Post.find("Status=0 and Title like '%:t%'").set("t",t).list()——这是错误做法,注意区分。


根据属性查询1(不需要联表查询)
List<TArticle> articles = TArticle.find( "Member.Id=7" )
.
select( "Id,Title,Member.Id,Cat.Name,Cat.ArticleCount,Board.Name" )
.
list();// ——警告:不推荐使用select方法。使用了select,虽然可以减少字段传输,但无法利用缓存;有时候还会和缓存冲突。如果你没有耐心调试,请勿使用。

根据属性查询2
List<TArticle> articles = TArticle.find( "Member.Id=:mid" )
.
set( "mid", 7 )
.
select( "Id,Title,Member.Id,Cat.Name,Cat.ArticleCount,Board.Name" )
.
list(); 

根据属性查询3(需要联表查询)
List<TArticle> articles = TArticle.find( "Member.Id=:mid and Cat.Name=:catname order by Id desc, Member.Id asc" )
.
set( "mid", 7 )
.
set( "catname", "音像世界" )
.
list();

查询全部
List<TCat> results = TCat.findAll();

查询全部(等效于findAll)
List<TArticle> articles = TArticle.find( "" ).list();

翻页
DataPage<Article> plist = Article.findPage( "IsDelete=0" );

int rd = plist.RecordCount; // 返回的结果数量
int pageCount = plist.
PageCount; // 共有几页
string pagerBar = plist.
PageBar; // html形式的翻页区,包括翻页链接
List<Article> 
list = plist.Results; // 结果集


翻页(参数带每页记录数)
DataPage<Article> plist = Article.findPage( "IsDelete=0", 25 ); //每页25条记录


直接使用 sql 查询
List<Article> list = Article.findBySql( "select * from Article" );

统计1
int count = TCat.count();

统计2
count = TCat.count( "Id=3" );

统计3
count = TArticle.count( "Member.Id=7" );

统计4
count = TArticle.count( "Author='周做人' " );

统计5(速度稍慢,但可以使用参数)
count = TArticle.find( "Member.Id=:mid" ).set( "mid", 7 ).count();

更新(全部属性更新)
Article article = Article.findById( 2 );
article.Title = "my new title";
article.update(); 


单独更新某个属性
Article article = Article.findById( 2 );
article.Title = "my new title";
article.update( "Title" ); 


批量更新
Article.updateBatch( "set IsDelete=1", "CategoryId=2" );

删除
Article article = Article.findById( 2 );
article.
delete(); 

批量删除
Article.deleteBatch( "CategoryId=2" );


排序
http://www.wojilu.com/Forum1/Topic/324


7、某些复杂的联表查询是不是不能使用?如何直接运行sql?
[答]是的。ORM虽然有点很多,但不是全能的。有些复杂的联表、统计查询,建议你直接使用sql语句。
其实,使用我记录ORM执行sql,是非常简单、高效的。
教程参看:http://www.wojilu.com/common/page/166


8、如何防止sql注入?

a)推荐使用参数化查询方式,比如 find( "" ).set( "", "" ).list() 这个是防sql注入的

b)其他如果要拼接字符串的话,需要自己过滤布安全字符。你也可以使用框架自带的一个简单的 strUtil.SqlClean 方法

c)大量的查询使用 ctx.PostInt 等获取强类型数据,能增强可靠性


9、多对多映射如何实现?对象继承如何实现?
关于“多对多”等关联操作:http://www.wojilu.com/forum1/topic/2105 
关于继承:http://www.wojilu.com/Forum1/Topic/159


10、日期比较如何实现?

参看:http://www.wojilu.com/Forum1/Topic/360 


11、如何获得插入之后的ID?
参看:http://www.wojilu.com/Forum1/Topic/327 


12、如何理解ORM中的一级缓存和二级缓存(透明缓存)?
参看:http://www.wojilu.com/forum1/topic/4246 
和:http://www.wojilu.com/Forum1/Post/2165 


13、如何将对象的属性映射到数据库字段?如果属性名称和字段名称不一致的话。

 [Table("你的表名称")]
public class Article {

    [Column(Name="你的列名称")]
    public String Name {get;set;}

}

如上图蓝色部分,加上 Column 批注,可以映射字段,加上 Table 批注,可以映射表名称。


14、如何给所有的数据表加上前缀?

打开 /framework/config/orm.config,填写TablePrefix(下图红字部分),然后重启网站或程序。 

{
    ConnectionStringTable:{......},

    AssemblyList:["......"],

    TablePrefix:"此处填写table前缀",
    ApplicationCache:true,
    ......其他配置

}

注意行末的逗号。如果还有下一行,请加上逗号。



本帖于 2013/9/5 9:24:15 被 掷鸡蛋者 最后编辑
关键词 ORM 修改tag
相关文章
而死,不默而生
zycheer
发表于: 2010/5/25 9:53 引用 回复 只看该作者 2# TOP
江湖大侠
性别: 男
积分:930
阅读权限:541
帖子: 127
加入时间: 2010/5/4
最后登录: 2013/8/23
沙发
xiao4316
发表于: 2010/5/25 10:04 引用 回复 只看该作者 3# TOP
江湖豪侠
性别: 男
积分:1405
阅读权限:739
帖子: 139
加入时间: 2010/5/18
最后登录: 2017/11/28
写得很具体 很好
掷鸡蛋者
发表于: 2010/5/25 10:26 引用 回复 只看该作者 4# TOP
管理员
性别: 男
积分:52151
阅读权限:43363
帖子: 8307
加入时间: 2010/4/29
最后登录: 2017/12/14
谢谢上面的支持
而死,不默而生
wt0731
发表于: 2010/5/25 13:40 引用 回复 只看该作者 5# TOP
江湖豪侠
性别: 男
积分:1308
阅读权限:841
帖子: 176
加入时间: 2010/4/29
最后登录: 2015/10/21
迈入人生关键时期! 我运营的网站http://www.djhnjllm.com/
zycheer
发表于: 2010/5/25 19:44 引用 回复 只看该作者 6# TOP
江湖大侠
性别: 男
积分:930
阅读权限:541
帖子: 127
加入时间: 2010/5/4
最后登录: 2013/8/23
看来有得必有失。Object RunScalar<T>( String sql ) 这个如何防注入。
那些select 不建议使用,与缓存有关系?
掷鸡蛋者
发表于: 2010/5/25 20:36 引用 回复 只看该作者 7# TOP
管理员
性别: 男
积分:52151
阅读权限:43363
帖子: 8307
加入时间: 2010/4/29
最后登录: 2017/12/14
看来有得必有失。Object RunScalar<T>( String sql ) 这个如何防注入。
那些select 不建议使用,与缓存有关系?
zycheer at 2010-5-25 19:44

 是的,直接使用sql就不能使用使用参数,所以防注入需要自己管理。当然,如果你要想直接通过DbContext获取connection,再通过原生的Command参数化执行sql也行,那样就彻底的使用底层数据库操作了。

因为select 只是选取了部分的属性到对象中,所以下次从缓存中取出的结果,仍然只有部分属性有结果。这个会让人造成很大的困惑。比如先是通过select( "" ).list() 选取了10条结果,然后又在另外一处findById() 获取了某个结果,如果正好在缓存范围,并且findById的ID在上一次的10条结果里,则第二次查询直接从缓存取出。

本来你findById的用意是获取完整的对象,但实际却是从第一次的select("").list() 的缓存中获取的不完全对象——这个容易造成未知的bug。

而死,不默而生
zycheer
发表于: 2010/5/25 20:49 引用 回复 只看该作者 8# TOP
江湖大侠
性别: 男
积分:930
阅读权限:541
帖子: 127
加入时间: 2010/5/4
最后登录: 2013/8/23
那这个如何解决呢。怎么使用不会产生这种情况。
掷鸡蛋者
发表于: 2010/5/25 22:53 引用 回复 只看该作者 9# TOP
管理员
性别: 男
积分:52151
阅读权限:43363
帖子: 8307
加入时间: 2010/4/29
最后登录: 2017/12/14
那这个如何解决呢。怎么使用不会产生这种情况。
zycheer at 2010-5-25 20:49

 当初设计了这个功能用于某些特殊场合,一般情况下我也不用select。因为ORM自带一级缓存,所以这方面的性能基本没有什么大的影响。也就是说,不推荐使用select。

而死,不默而生
xiaoyi1234
发表于: 2010/5/26 10:22 引用 回复 只看该作者 10# TOP
江湖少侠
性别: 男
积分:360
阅读权限:139
帖子: 26
加入时间: 2010/4/29
最后登录: 2015/9/26

哈哈 不好意思 我又来了

这个ORM 有不少是我喜欢的 我喜欢的理由是 有适合我即将开发的项目的

东东

所以 我想弱弱的问一下,

我可不可以直接只使用ORM或者

wojilu json
wojilu ajax

等,因为我的项目是WEBFORM方式的

所以问一下 看代码我都看晕了 哈哈

是不是里面的东东只能用于此MVC模式下啊

如果可以 能否就这个方面 做一个简单的介绍

简单的说一下使用方式 就可以了 其他我慢慢摸索 谢谢

 

快速回复主题