Gentle.NET 使用文档
------------------------------------------------------------
概述
------------------------------------------------------------
介绍
Gentle.NET是一个开源的优秀O/R Mapping的对象持久化框架。介绍就不多说了,以下是原文:
Gentle.NET is an RDBMS independent object persistence framework. It features automatic SQL generation and object construction, and SQL factory for creating custom queries, DataView construction helpers, excellent performance and reasonably complete docs.
Gentle.NET是一个关系数据库中立的(RDBMS indenpendent)对象持久化框架。它具有以下特征:
·自动构建SQL
·自动创建实体对象
·用于创建定制查询的SQL工厂
·DataView创建助手
·优秀的性能
·合理完善的文档
相关资源
官方首页:http://www.mertner.com/confluence/display/Gentle/Home
开发团队:http://www.mertner.com/confluence/display/Gentle/Project+Team
最新文档:http://www.mertner.com/confluence/display/Gentle/Documentation+Home
开发进度:http://www.mertner.com/jira/browse/GOPF
例程下载:http://www.mertner.com/confluence/display/Gentle/Sample+Projects
开发计划:http://www.mertner.com/confluence/display/Gentle/Open+Tasks
OR映射: http://www.15seconds.com/issue/040112.htm
最新版本
1.2.9 2006-06
安装包中(1.2.9)的内容
Build
Nant编译文件,强名密钥文件,NDoc文档生成文件等
Configuration
App.config和Gentle.Config配置文件,这两个文件差不多,只是app.config多了个log4net配置节
App.config配置文件要根据情况改成web.config
Gentle.Config只要放到与项目编译生成程序集相同的目录下就行了,组件自己会去搜寻这个配置文件
只要使用一个就可以
Contributions
MyGeneration和CodeSmith的代码生成模板
Documentation
帮助文档。
Gentle API.chm:GentleAPI介绍文档。估计也是用工具自动生成的。
GentleDocumentation.pdf:顺序混乱使用文档,最好根据左侧的目录树来导航。该文件中的UserGuide部分要好好看看
Output
dll文件。里面存放的是已经编译的好的程序集(Release版),可以直接拷出来使用
Source
gentle源代码
Gentle.Framework.Tests 测试例程
Gentle 2.*开发计划
Morten Mertner对gentle的发展方向非常明确,并提出了野心勃勃的2.x版本开发计划(http://www.mertner.com/confluence/display/gentle/open+tasks),着重于提高gentle的使用便利性。大致浏览了一下,以下功能我颇感兴趣:
扩展日志模块,允许使用自定义的日志记录器
查询方面的增强
·所有查询对象和查询结果都可序列化
·添加分页支持
·增强对关系查询(joins)的支持
·添加lazy load功能
·添加创建/删除表的支持
·添加OPath功能(用于对象查询,类似ibastic的HQL)
VisualStudio插件
·可查找Gentle类
·创建gentle包装代码
·直接在VS中创建相应的数据库表
·扩展类设计器,允许使用Gentle attribute来修饰类
------------------------------------------------------------
使用
------------------------------------------------------------
1.加入Gentle.Net程序集引用
Gentle.Common.dll
Gentle.Framework.dll
Gentle.Provider.*.dll
2.修改gentle配置文件
(1)修改Gentle.config文件中的<DefaultProvider>和<Providers>部分
(2)把Gentle.Config拷贝到项目内
·项目根目录下
·项目子目录config下
·任意位置。需要在web.config中指明gentle配置文件路径<add key='GentleConfigFolder' value='./Gentle2.config'/>
3.创建数据库表和视图
4.使用代码工具CodeSmith或MyGeneration等生成Gentle类文件
5.使用这些类。这些类提供了基本的选取和修改的功能,可手动修改该文件以满足自定义功能
------------------------------------------------------------
MyGeneration生成的gentle类代码示例
------------------------------------------------------------
以留言簿数据表的gentle类包装为例:
(1)留言簿的数据字典
id 自增数字字段
name 字符串
email 字符串
web 字符串
ip 字符串
title 字符串
content 字符串
createDate 时间日期
(2)MyGeneration生成的包装类。代码非常紧凑干练,排版风格我也很喜欢:>。
[TableName('GuestBook', CacheStrategy.Temporary)]
public class GuestBook : Persistent
{
#region Members
private bool isChanged;
[TableColumn('id', NotNull=true), PrimaryKey(AutoGenerated=true)]
protected int id;
[TableColumn('name', NullValue='')]
protected string name;
[TableColumn('email', NullValue='')]
protected string email;
[TableColumn('web', NullValue='')]
protected string web;
[TableColumn('ip', NullValue='')]
protected string ip;
[TableColumn('title', NullValue='')]
protected string title;
[TableColumn('content', NullValue='')]
protected string content;
[TableColumn('createDate')]
protected DateTime createDate;
#endregion
#region Constructors
/// <summary>
/// Create a new object using the minimum required information (all not-null fields except
/// auto-generated primary keys).
/// </summary>
public GuestBook()
{
isChanged = true;
id = 0;
}
/// <summary>
/// Create a new object by specifying all fields (except the auto-generated primary key field).
/// </summary>
public GuestBook(string name, string email, string web, string ip, string title, string content, DateTime createDate)
{
isChanged = true;
this.name = name;
this.email = email;
this.web = web;
this.ip = ip;
this.title = title;
this.content = content;
this.createDate = createDate;
}
/// <summary>
/// Create an object from an existing row of data. This will be used by Gentle to
/// construct objects from retrieved rows.
/// </summary>
public GuestBook(int id, string name, string email, string web, string ip, string title, string content, DateTime createDate)
{
this.id = id;
this.name = name;
this.email = email;
this.web = web;
this.ip = ip;
this.title = title;
this.content = content;
this.createDate = createDate;
}
#endregion
#region Public Properties
public bool IsChanged
{
get { return isChanged; }
}
/// <summary>
/// Property relating to database column id
/// </summary>
public int Id
{
get { return id; }
}
/// <summary>
/// Property relating to database column name
/// </summary>
public string Name
{
get { return name; }
set { isChanged |= name != value; name = value; }
}
/// <summary>
/// Property relating to database column email
/// </summary>
public string Email
{
get { return email; }
set { isChanged |= email != value; email = value; }
}
/// <summary>
/// Property relating to database column web
/// </summary>
public string Web
{
get { return web; }
set { isChanged |= web != value; web = value; }
}
/// <summary>
/// Property relating to database column ip
/// </summary>
public string Ip
{
get { return ip; }
set { isChanged |= ip != value; ip = value; }
}
/// <summary>
/// Property relating to database column title
/// </summary>
public string Title
{
get { return title; }
set { isChanged |= title != value; title = value; }
}
/// <summary>
/// Property relating to database column content
/// </summary>
public string Content
{
get { return content; }
set { isChanged |= content != value; content = value; }
}
/// <summary>
/// Property relating to database column createDate
/// </summary>
public DateTime CreateDate
{
get { return createDate; }
set { isChanged |= createDate != value; createDate = value; }
}
#endregion
#region Storage and Retrieval
/// <summary>
/// Static method to retrieve all instances that are stored in the database in one call
/// </summary>
static public IList ListAll()
{
return Broker.RetrieveList(typeof(GuestBook));
}
public static GuestBook Retrieve(int id)
{
Key key = new Key(typeof(GuestBook), true, 'id', id);
return Broker.RetrieveInstance(typeof(GuestBook), key) as GuestBook;
}
public static GuestBook ComplexRetrieve(int id)
{
throw new NotImplementedException('Gentle.NET Business Entity script: Generation of complex retrieve function (multiple primary keys) is not implemented yet.');
//return null;
}
public override void Persist()
{
if (IsChanged || !IsPersisted)
{
base.Persist();
isChanged = false;
}
}
public override void Remove()
{
base.Remove();
}
#endregion
}
(3)如上,该类实现了基本的CRUD操作
增:GuestBook entity = new GuestBook(...); entity.Persist();
查:GuestBook entity = GuestBook.Retrieve(id); 或 IList list = GuestBook.RetrieveAll();
改:GuestBook entity = GuestBook.Retrieve(id); ...; entity.Persist();
删:GuestBook.Retrieve(id).Remove;
(4)扩展该类
·默认的删除函数效率比较低下,建议创建静态函数
public static void Remove(int id)
{
Key key = new Key(typeof(GuestBook), true, 'id', id);
Broker.Remove(typeof(GuestBook), key);
}
调用时直接用GuestBook.Remove(id)就好了
·建议添加PrePersist()和PreRemove()虚函数,方便业务层的扩展,如文件操作,关联数据表删除操作等
·可参考文章gentle.net bugs fixing
------------------------------------------------------------
例程
------------------------------------------------------------
【新建】
直接调用Broker.Insert()函数
Category category = new Category();
Gentle.Framework.Broker.Insert(category);
若Category继承至Persistent类,则直接调用Persist()函数来保存
Category category = new Category(....);
category.Persist();
【删除】
// e.g. Product.Retrieve(id).Remove();
public void Remove()
{
base.Remove();
}
// e.g. Product.Remove(id);
public static void Remove(int id)
{
Key key = new Key(typeof(Product), true, 'id', id);
Broker.Remove(typeof(Product), key);
}
【查询】
获取单条记录
// e.g. Category entity = Category.Retrieve(1);
public static Category Retrieve(int id)
{
Key key = new Key(typeof(Category), true, 'CategoryID', id);
return Broker.Retrieve(typeof(Category), key) as Category;
}
获取记录集
无参数限制
static public IList ListAll()
{
return Broker.RetrieveList( typeof(User) );
}
根据一个参数获取记录集
static public IList ListTeamMembers(int teamId)
{
Key key = new Key(typeof(Act), true, 'teamId', teamId);
return Broker.RetrieveList(typeof(Member), key);
}
根据两个参数获取记录集
static public IList ListTeamMemberAct(int teamId, int memberId)
{
Key key = new Key(typeof(Act), true, 'teamId', teamId, 'memberId', memberId);
return Broker.RetrieveList(typeof(Act), key);
}
多个参数获取记录集
static public IList ListTeamMemberAct(int teamId, int memberId, int otherId)
{
Key key = new Key(typeof(Act), true, 'teamId', teamId, 'memberId', memberId);
key.Add('otherId', otherId);
return Broker.RetrieveList(typeof(Act), key);
}
SqlBuilder定制查询(模糊查询,过滤查询)
// 流程:SqlBuilder-->SqlStatement-->SqlResult-->DataView | TypedArrayList
// 注:particalName必须使用通配符,如'Kev%'
static public IList ListByNameStartsWith( string partialName )
{
SqlBuilder sb = new SqlBuilder(StatementType.Select, typeof(User));
sb.AddConstraint(Operator.Like, 'Name', partialName);
sb.AddConstraint('substr(coalmineid,4,3)='101'');
sb.AddConstraint('rownum=1');
sb.AddOrderByField('id');
SqlStatement stmt = sb.GetStatement(true);
SqlResult sr = Broker.Execute(stmt);
return ObjectFactory.GetCollection(typeof(User), sr);
//return ObjectView.GetDataView(sr);
}
Criteria语法?
Criteria criteria = session.createCriteria(TUser.class);
criteria.add(Expression.eq('groupId', new Integer(2)));
返回值类型
Object
return Broker.Retrieve(typeof(Category), key) as Category;
SqlResult
return Broker.Execute(sql);
return Broker.Execute(sqlStatement);
IList(TypeArrayList)
return Broker.RetrieveList( typeof(User) );
return Broker.RetrieveList( typeof(User), key );
TypedArrayList customerList = new TypedArrayList( typeof(Customer) );
return Broker.RetrieveList( typeof(Customer), customerList );
return ObjectFactory.GetCollection(typeof(User), sqlResult);
DataView
return ObjectView.GetDataView(sqlResult);
GentleList?
排序
SqlBuilder排序
SqlBuilder sb = new SqlBuilder(StatementType.Select, typeof(User));
sb.AddConstraint(Operator.Like, 'Name', partialName);
sb.AddOrderByField('id');
对TypedArrayList对象排序?
直接写SQL的orderby排序?
关联的实现方案
public class User
{
// 获取与account相关联的account对象列表
public IList Accounts
{
get{ return RetrieveList( typeof(Account), 'Id' ); }
}
}
【更新】
1.最简单的更新
User user = User.Retrieve(id);
user.Name = 'Kevin';
user.Persist();
2.如果想要改变数据的主键,就没有那么方便了,只能是先删除-然后改变状态-然后改变主键-最后再插入保存
private void btnUpdateKey_Click(object sender, System.EventArgs e)
{
try
{
UT_BM_COALMINE cm=UT_BM_COALMINE.Retrieve('1201010001');
cm.Remove();
cm.IsPersisted=false;
cm.COALMINEID='120101000a';
cm.Persist();
}
catch(GentleException ex)
{
if(ex.Error==Gentle.Common.Error.UnexpectedRowCount)
this.ShowMessage('要更新的数据并不存在!'+ex.Error.ToString ());
else
throw;
}
}
【直接写sql】
private SqlResult ExecuteSql(string sql)
{
return Broker.Execute(sql);
}
private DataView ExecuteSql(string sql)
{
SqlResulte sr = Broker.Execute(sql);
return ObjectView.GetDataView(sr);
}
private IList FindUsers(string filter)
{
SqlResult sr = Broker.Execute('Select * from User where ' + filter);
return ObjectFactory.GetCollection(typeof(User), sr);
}
【调用存储过程: 有点繁杂】
// GentleSqlFactory
GentleSqlFactory sqlFact = Broker.GetSqlFactory();
// IDbCommand & IDataParameter
IDbCommand cmd = sqlFact.GetCommand();
cmd.CommandType = CommandType.StoredProcedure;
IDataParameter param = cmd.CreateParameter();
param.ParameterName = sqlFact.GetParameterPrefix() + 'CustomerId' + sqlFact.GetParameterSuffix();
param.Value = 'ALFKI';
cmd.Parameters.Add(param);
// SqlStatement
SqlStatement sqlStat = new SqlStatement(Gentle.Framework.StatementType.Unknown, cmd, 'CustOrderHist');
// SqlResult
SqlResult sqlRes = Broker.Execute(sqlStat);
dataGrid1.DataSource = ObjectView.GetDataView(sqlRes);
【事务处理transaction】
try
{
Transaction transaction = new Transaction();
transaction.Persist( obj );
transaction.Commit();
}
catch( Exception e )
{
transaction.Rollback();
throw;
}
【xml序列化】
public static void SerializeToFile( object obj, string fileName )
{
// remove Persistent.IsPersisted attribute
XmlAttributes attrs = new XmlAttributes();
// create an XML element for IsPersisted
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = 'IsPersisted';
attr.Type = typeof(bool);
// add the element to the collection of excluded elements
attrs.XmlElements.Add( attr );
attrs.XmlIgnore = true;
// add attribute overrides to hide IsPersisted property of Gentle's Persistent class
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
attrOverrides.Add( typeof(Persistent), 'IsPersisted', attrs );
// serialize object
FileStream fs = new FileStream( fileName, FileMode.Create );
System.Xml.Serialization.XmlSerializer xml =
new System.Xml.Serialization.XmlSerializer( obj.GetType(), attrOverrides );
xml.Serialize( fs, obj );
...
}
【对象比较】
对象是否完全相同(根据hash值)
public override int GetHashCode()
{
PropertyHolder holder = this;
return holder.Id.GetHashCode() +
holder.Name.GetHashCode() +
holder.TInt.GetHashCode() +
holder.TDecimal.GetHashCode() +
holder.TDouble.GetHashCode() +
holder.TBool.GetHashCode() +
holder.TDateTime.GetHashCode() +
holder.TDateTimeNN.GetHashCode() +
// make sure space padding (added by db) is ignored
holder.TChar.TrimEnd().GetHashCode() +
holder.TNChar.TrimEnd().GetHashCode() +
holder.TVarChar.GetHashCode() +
holder.TNVarChar.GetHashCode() +
holder.TText.GetHashCode() +
holder.TNText.GetHashCode();
}
public override bool Equals( object obj )
{
if( obj.GetType() != this.GetType() )
return false;
PropertyHolder holder1 = (PropertyHolder) obj;
PropertyHolder holder2 = this;
return holder1.GetHashCode() == holder2.GetHashCode()
&& holder2.GetHashCode() == holder1.GetHashCode();
}
------------------------------------------------------------
【常用的Gentle类】
关于SqlStatement
存储Sql语句及相关环境变量
public SqlStatement( StatementType stmtType, IDbCommand cmd, string sql )
public SqlStatement(
PersistenceBroker broker,
StatementType stmtType, IDbCommand cmd, string sql,
Type type, int rowLimit, int rowOffset )
public SqlResult Previous()
public SqlResult Next()
public SqlResult Page( int page )
关于SqlBuilder
用于构造适合特定数据库类型的SQL语句.可构造的SQL语句类型有
public enum StatementType
{
Unknown, //
Select, // 调用 ExecuteReader()
Count, // 调用 ExecuteScalar()
Identity, // 调用 ExecuteScalar()
Insert, // 调用 ExecuteScalar() 或 ExecuteNonQuery()
Update, // 调用 ExecuteNonQuery()
Delete, // 调用 ExecuteNonQuery()
SoftDelete // 调用 ExecuteNonQuery()
}
添加列(构造select语句)
void AddFields( Type type ); // 添加所有拥有TableColumn特性的成员
void AddKeyFields( Type type, bool isParameter ); // 添加所有拥有TableColumn和PrimaryKey特性的成员
添加约束(用于构造where子句)
sb.AddConstraint(Operator.Like, 'Name', partialName);
sb.AddConstraint('substr(coalmineid,4,3)='101'');
sb.AddConstraint('rownum=1');
public enum Operator
{
Equals,
NotEquals,
Like,
NotLike,
LessThan,
LessThanOrEquals,
GreaterThan,
GreaterThanOrEquals,
In,
NotIn
} ;
添加排序(order by 子句)
void AddOrderByField( bool isAscending, string fieldName );
void AddOrderByField( string orderClause );
记录偏移
void SetRowLimit( int rowLimit )
void SetRowOffset( int rowOffset )
构造SQL语句的基本原理(以SQLServer的Select语句构造为例):
sql = Format( fmtSelect, GetTopLimit(), AsCommaList( quotedFields ),
GetTableName( tableName ), GetConstraints(), GetOrderBy(), '', '' );
关于SqlResult
/// The SqlResult class serves as a multi-purpose encapsulation of query results,
/// including access to error codes and information on sql errors, query info
/// (rows affected/returned), and similar information.
公共属性
public int ErrorCode
public Exception Error
public string ErrorMessage
public int RowsContained
public int RowsAffected
public int LastRowId
public int Count
public string[] ColumnNames
public int GetColumnIndex( string columnName )
public SqlStatement Statement
数据访问
public ArrayList Rows
public object[] this[ int rowIndex ]
public object this[ int rowIndex, int columnIndex ]
public object this[ int rowIndex, string column ]
分页处理
public SqlResult Previous()
public SqlResult Next()
public SqlResult Page( int page )
辅助函数
public string GetString( int rowIndex, string column )
public bool GetBoolean( int rowIndex, string column )
public DateTime GetDateTime( int rowIndex, string column )
public int GetInt( int rowIndex, string column )
public long GetLong( int rowIndex, string column )
public double GetDouble( int rowIndex, string column )
public decimal GetDecimal( int rowIndex, string column )
public object GetObject( int rowIndex, string column )
------------------------------------------------------------
火花
------------------------------------------------------------
对于非自增且非空字段,gentle自动代码工具会自动生成倚赖该字段的构造函数,如
public Account(string account)
{
isChanged = true;
id = 0;
this.account = account;
}
如何实现join功能
gentle.net不支持join,但有替代方法
·使用视图
·使用GentleList
·手工写SQL: SqlBuilder, SqlStatement
·使用QueryDom(http://sourceforge.net/projects/qdom/)
gentle.net 1.3中将整合进更多改进的查询功能
如何提升ASP.NET使用gentle的性能
使用缓存,更改UniqueScope设置(如WebSession)
尽量关闭Session?