Configuration 配置
SubSonic Configuration Section SubSonic配置节
首先,在Web.config文件中,在<configSections>内增加一个SubSonic配置节。这种默认配置应该对大多数项目有用。
<configSections>
<sectionname="SubSonicService" type="SubSonic.SubSonicSection,SubSonic"
allowDefinition="MachineToApplication"restartOnExternalChanges="true"
requirePermission="false"/>
</configSections>
Data Provider 数据供给者
第二,您将需要设置一个数据提供者。目前被SubSonic支持的有三个: SQL Server,MySQL和Enterprise Library。下面是这三个的示例配置。这些信息也添加在<configSections>内。
<SubSonicService defaultProvider="SqlDataProvider"spClassName="SPs"
fixPluralClassNames="true">
<providers>
<add name="SqlDataProvider"type="SubSonic.SqlDataProvider, SubSonic"
connectionStringName="NorthwindConnection"/>
<add name="ELib2DataProvider"type="ActionPack.ELib2DataProvider,
ActionPack"connectionStringName="NorthwindSQL"/>
<add name="MySqlDataProvider"type="ActionPack.MySqlDataProvider,
ActionPack"connectionStringName="NorthwindMySQLConnection"/>
</providers>
</SubSonicService>
在<SubSonicService>内有五个值可以设置。
1. defaultProvider
多个供应者可以在配置内设置。这个值表示使用的是哪个供应者。
2. fixPluralClassNames
SubSonic可以从表名末尾删除复数字符,以使类别名一致。例如,产品表会显示产品类别。
3. generatedNamespace
默认情况下产生的所有类别将是该项目的全局命名空间的一部分。这个值忽略那种行为,并且在特定的命名空间包含所有类别。例如,通过设置这值为
Northwind你会获得Northwind.Product。
4. spClassName
每个存储过程会产生相同名称的一种方法。这个值是将这些方法包含在其中的类。例如,通过设置这值为SPs,CustOrderHist存储过程将会成为SPs.CustOrderHist 。使用上述命名空间例子与这个值相结合将会产生Northwind.SPs.CustOrderHist 。
5. templateDirectory
有可能覆盖SubSonic产生的代码。此目录将包含的代码模板,以取代默认模板提供的。这将会在稍后讨论代码生成模板时更详细地讲解。
6. useSPs
如果你不想要一个为存储程序而产生的类,设置此值为false。
Database Connection String 数据库连接字符串
第三,你需要定义一个数据库连接字符串。
<connectionStrings>
<addname="NorthwindConnection" connectionString="Data
Source=localhost\SQLExpress; Database=Northwind;Integrated Security=true;"/>
</connectionStrings>
Build Provider Configuration 建立供应商配置
第四,你需要设置一个建立供应商来产生自动生成的类。这需要在<compilation>内添加。
<buildProviders>
<add extension=".abp"type="SubSonic.BuildProvider, SubSonic"/>
</buildProviders>
Build Provider Definition 建立供应商的定义
最后,您需要创建一个.abp 文件供此建立供应商使用。通过在 App_Code 文件夹中增加一个命名为 Builder.abp 的文本文件来这样做。在这个文件中你说明哪些数据库表应该有自动生成类。如果你想所有表格,只需输入*,否则,每行一个的列出各个表。
Summary 总结
总之,这些是你需要配置的项。
SubSonic Configuration Section 配置节
Data Provider 数据供应者
Database Connection String 数据库连接字符串
Build Provider Configuration 建立供应商配置
Build Provider Definition 建立供应商定义
这里是一个范例Web.config中的所有SubSonic要求的值的定义。您也可以将Web.config包含于下载的范例网站中,和SubSonic的源代码一起作为一个起始点,这是这些示例值是来源。
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionname="SubSonicService" type="SubSonic.SubSonicSection,
SubSonic"allowDefinition="MachineToApplication"
restartOnExternalChanges="true"requirePermission="false"/>
</configSections>
<appSettings/>
<connectionStrings>
<addname="NorthwindConnection" connectionString="Data
Source=localhost\SQLExpress;Database=Northwind; Integrated
Security=true;"/>
</connectionStrings>
<SubSonicServicedefaultProvider="SqlDataProvider" spClassName="SPs"
fixPluralClassNames="true">
<providers>
<add name="SqlDataProvider"type="SubSonic.SqlDataProvider,
SubSonic"connectionStringName="NorthwindConnection"/>
</providers>
</SubSonicService>
<system.web>
<compilation debug="true"defaultLanguage="C#">
<buildProviders>
<add extension=".abp"type="SubSonic.BuildProvider, SubSonic"/>
</buildProviders>
<assemblies>
<add assembly="System.Management,Version=2.0.0.0,
Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
<addassembly="System.Data.OracleClient, Version=2.0.0.0,Culture=neutral,PublicKeyToken=B77A5C561934E089"/>
<addassembly="System.Configuration.Install, Version=2.0.0.0,
Culture=neutral,PublicKeyToken=B03F5F7F11D50A3A"/>
<add assembly="MySql.Data,Version=1.0.7.30072, Culture=neutral,
PublicKeyToken=C5687FC88969C44D"/>
</assemblies>
</compilation>
<authenticationmode="Windows"/>
</system.web>
</configuration>
为了确保一切工作,建立网站,然后打开类视图窗口,您应该可以看到与表格相匹配的类名。例如,使用Northwind数据库,您现在应该可以看到命名Category,Customer和Employee的类。
Trust Level 信任水平
建立供应商将不会在中等信任的环境中工作,他们需要充分的信任。如果你计划让别人托管你的应用程序这可能是一个问题。大多数托管服务提供商在完全信任的环境中不会装配运行。作为一个工作循环,在SubSonic启动套件中提供两个类产生器,这将稍后详细讲解,其中以文本方式输出可以在你的应用里包含并直接编辑的代码。
目前两个对于主办规则的例外是Ultima Hosts和Discount ASP.net 。在SubSonic项目开始前协调托管服务提供商是一个好方法。
Classes 类
SubSonic 的核心,最实用的特征便是自动生成出来的类。正如之前的叙述,会有一个关于数据库中每一张数据表的类。之后的一些部分将深度研究所提供的功能。在这部分中的实例将会用到 Northwind 数据库中的 Products 数据表作为基础。
Extending the Model 扩展模型
SubSonic 的创造者意识到没有任何一个模型能够容纳每个人的需求。除了为你提供源代码去修改,还有另一种方法你能够接受并且扩展生成的模型而不必去修改基础的核心代码。SubSonic 创建了分部类,它是在.NET 2.0 中被引进使代码生成工具更容易实现的机制。分部类允许你添加附加的属性和方法而不必去修改已生成的代码也不必担心生成过程会重写了你的改动。
Constructors 构造函数
直接创建一个新的对象。
Product product = new Product();
还有两个被重载的构造函数用于载入在数据库中已经存在的对象。在探讨 SubSonic 的多种
检索数据的方法时,它们也会被涵盖。
Properties 属性名
每个对象会对从相应的数据表中获得的每一列用一个属性名来标识。所以 Product 对象会包
含以下属性名:CategoryID、Discontinued、ProductID、ProductName、QuantityPerUnit、ReorderLevel、SupplierID、UnitPrice、UnitsInStock 和 UnitsOnOder。
Rules Enforcement 强制性规则
没有任何一个属性强制执行任何授权、验证或商业规则。那是由您来决定的。如何在商业规
则下有效地实施这些规则会在之后探讨。
Object Key 对象主键
每个对象会有一个主键属性,比如在 Product 数据表中那个主键是 ProductID。SubSonic 利用这个属性名作为对象 ID 因为 ProductID 在数据库中被定义为主键。(SubSonic 对没有主键
的数据表不起作用。)一般的数据表拥有三种不同主键中的一种:GUID,一种自动增长的整数或自然数的键。能够代表 GUID 的任何键,包括整型或字符串型,都涵盖其中。还未交代的一件事是对多主键的支持。
State 状态
有三个属性帮助你管理对象的当前状态:
IsDirty – 是否对象已经改变却没有存入到数据库中?
IsLoaded – 对象从数据库中读取出来了么?
IsNew – 对象在存储体中创建了么?换句话说,这个对象在数据库中不存在。
Columns 列
有时你需要传递字符串形式的列名作为方法参数,如同您在之后看到的 FetchByParameter方法。不必逐字输入字符串,您可以使用每个类建造的静态 Columns collection。
Product.Columns.ProductName
也可以通过调用每个对象建造的 GetColumnValue 方法,传入列名来获取某一列的值。
product.GetColumnValue(Product.Columns.ProductName);
Retrieving a Single Object 检索单个对象
可以通过使用三种重载的读取方法中的一种,传入 DataRow、DataTable 或 DataReader 之一在对象级读取数据。然而您更有可能使用静态的 FetchByID 方法或者重载的构造函数。FetchByID FetchByID 函数
FetchByID 有一个参数,在 GUID 中对象主键的值,整型或字符串型,并且返回一个限定的
对象。
Productproduct = Product.FetchByID(id);
如果对象没有找到,SubSonic 也不会抛出错误。取而代之的是您应该查看下主键属性是否
符合传入的 ID 来决定对象是否能被找到。
int id =1;
Productproduct = Product.FetchByID(id);
if(product.ProductID == id)
{
//Success
}
else
{
// NotFound
}
Constructor 构造函数
使用重载的构造函数的方法同样可以像下面这样去获取主键。
Productproduct = new Product(id);
列名和值作为参数,通过使用另一个重载的构造函数,可以读取基于其它的唯一标识列的对
象来代替主键检索。
Productproduct = new Product(Product.Columns.ProductName, "Chai");
当使用这种形式检索时,请务必注意。如果您所使用的列没有唯一限制并且有多于一条的数
据库返回记录,您的对象将被第一条记录所限定。
Loading and Saving State 读取和存储状态
还有另一种读取对象的方法。每个对象都有个名为 NewFromXML 的方法用于将 XML 字符串
创建为对象。这个方法显然要与将对象的状态写入暂存空间例如会话状态的 ToXML 方法搭配使用。
Session["Product"]= product.ToXML();
product= (Product)product.NewFromXML(Session["Product"].ToString());
RetrievingMultiple Objects 检索多个对象
FetchAll FetchAll 函数
返回多个对象最简单的方法便是静态方法FetchAll。正如它方法名的意思一样,以DataReader 形式返回在数据库中相应类型的每一个对象,使得它很容易实现对数据操控的屏蔽就像 GridView。
GridView1.DataSource= Product.FetchAll();
GridView1.DataBind();
你也可以把 SubSonic 的排序传入FetchAll 方法。
GridView1.DataSource=
Product.FetchAll(SubSonic.OrderBy.Desc(Product.Columns.ProductName));
Find 函数
静态方法 Find 允许您检索基于已经存在对象的匹配记录。例如,如果您需要找出所有SupplierID 为 1 并且 CategoryID 为 1 的 Products,您可以创建一个写入那些值的新对象,并把它传入 Find 方法。
Productproduct = new Product();
product.SupplierID= 1;
product.CategoryID= 1;
GridView1.DataSource= Product.Find(product);
Find 方法也可以考虑传入排序。
Querying 查询
如果没有一种 Fetch 或 Find 方法能够在实践中起作用,您仍然可以回归到 SubSonic 查询或之后要探讨的存储进程。
Updating the Database 数据库更新
将您的更改保存到数据库只需调用当前对象的 Save 方法一般简单。
product.Save();
但是了解您在调用这个方法时发生了什么是非常重要的。上面的那个例子无法传递当前用户的信息。正如您会在之后探讨协定时看到,SubSonic 拥有保持一些基本历史信息的能力。如果您的数据表被设定去记录这条信息,您需要传递整型或者 GUID 型的 User ID,或者字符串格式的 User Name。
product.Save(User.Identity.Name);
如果主键是 GUID 或者自增加整数而且对象是新的,保存过程将会更新对象的主键属性。保存过程也会把 IsNew 和 IsDirty 属性设为否。
Insert and Update 插入和更新
通过静态类的方法插入或更新数据同样是可行的。
Product.Insert("Product Name", 1,1, "10", 10.00, 10, 10, 1, false);
Product.Update("Product Name", 1,1, "10", 10.00, 10, 10, 1, false);
这些方法做了实例化对象,设定属性和调用 Save 方法的所有工作。缺点就是没有任何一个方法返回自动生成的主键的值。
Deleting 删除
有两种删除方式:逻辑的和永久的。逻辑删除并不从数据库中删除记录,而是把一列用于标识记录被删除。SubSonic 会把这个称作“Deleted”或者“IsDeleted”的列作为标志位。为了实现逻辑删除,您的数据表必须其中有一列定义为 1 比特,之后 IsDeleted 属性才能够在
对象中起作用被设定。当 Save 方法被调用时,对象会被标识为删除。还有一个叫做 Delete的静态方法通过获取对象的键值能够达到同样的目的。
Product.Delete(product.ProductID);
注意这个例子将不会对默认的 Northwind 数据库起作用由于 Products 数据表没有任何格式的删除列。您需要去添加一个“Deleted”列使它运行。
不幸的是,在检索数据时 SubSonic 仅仅把它当作协定。您需要过滤掉被删除的记录,例如,当使用 FetchByParameter 方法时。永久性删除更加容易。只需要调用静态的 Destroy 方法。
Product.Destroy(product.ProductID);
Business Rules 商业规则
保存过程中有两处商业规则能够插入进来。保存过程开始时,PreUpdate 方法被调用并且结束时 PostUpdate 方法被调用。这些方法都是定义在每个类中不需要任何参数也没有返回值的虚函数。要定义这些方法,用和指定类相同的名称创建一个分部类文件。
public partial class Product
{
protected override void PreUpdate()
{
// Do something
}
protected override void PostUpdate()
{
// Do something
}
}
这是一种添加授权、验证和商业规则的简单方法。如果您需要更加灵活的方式,查询之后协
定里对 Controller 类型实现的探讨。
Underlying Data 下层数据
自动生成类也许给出基于接口的简单对象,但是表面之下数据存在于 ADO.NET 数据表里面。SubSonic 给出一些方法允许您获取下层的结构。TableName 属性返回关系到这个对象的实表名称。
product.TableName;
静态类的方法 GetTableSchema 返回下层数据表。
SubSonic.TableSchema.Table tableSchema =Product.GetTableSchema();
注意:还有个静态属性叫 Schema 能够返回相同的信息。使用这个属性时,类必须实例化至少一次。GetTableSchema 为您关注到了这点。在之后检查查询时这些方法都会被用到。Inspect 方法返回对象的 HTML 呈现并使用<table>作为标签。此方法有一个重载版本需要传入一个布尔参数 useHtml 设置为否去翻译回原来的文本。
string html = product.Inspect();
Collections
载入一个集合最简单的载入一个集合到内存的方法就是调用 Load 方法,在不给出任何参数的情况下,
该方法将返回集合的每一条记录。
ProductCollection products = newProductCollection();
products.Load();
也可以给 Load 方法一个参数,这个参数可以是 IDataReader, DataTable, 或者 SubSonicQuery 类型的。
IDataReader reader = Product.FetchAll();
products.Load(reader);
reader.Close();
(要确保在使用完之后写代码关闭 reader, 记住, Load 方法不会帮你关闭这个 reader.)
Ordering a Collection
按序取得一个集合
你可以根据某个单一行来排序集合。这样需要在调用 Load 方法之前使用 OrderByAsc 或OrderByDesc 方法来说明要进行升序或者降序的排序。
ProductCollection products = newProductCollection();
products.OrderByAsc(Product.Columns.ProductName);
products.Load();
Filtering a Collection
过滤一个集合的结果可以在调用Load方法之前通过使用BetweenAnd, Where 或者 WhereDatesBetween方法,过滤一个集合的取值结果。
OrderCollection orders = newOrderCollection();
orders.BetweenAnd(Order.Columns.OrderDate,new DateTime(1980, 1, 12),
DateTime.Now);
orders.Load();
在这里的 Where 方法作用的结果类似于 SubSonic Query Where 方法(这个方法将在下面的部分进行介绍)
Queries
除了上面介绍的在Fetch方法中用到的用于过滤查询结果的方法和在集合collection中使用的过滤方法外,SubSonic 同时提供了一种方式用于动态的生成 SQL 查询。这种情况下需要通过使用 CreateQuery 方法实例化一个 Query 实例。
SubSonic.Query query =Product.CreateQuery();
或者可以将表名作为参数传递给方法。
SubSonic.Query query = newSubSonic.Query(product.TableName);
也可以将数据表的 schema 作为参数传递给方法
SubSonic.Query query = newSubSonic.Query(Product.GetTableSchema());
最后一种方法可以放置 SubSonic 从数据库中读入表的具体信息,免除了再调用一个另外的
方法。
注释:也可以通过调用静态方法 BuildTableSchema 或者使用 Schema 属性来获取数据表对
象的 schema.
Running the Query
执行查询语句在 SubSonic 中执行 query 查询与在 ADO.NET 中执行 query 查询所遵循的要求是相同的。当使用 Execute 方法执行 query 查询时运行查询但不返回任何值。
query.Execute();
ExecuteDataSet 方法返回一个DataSet
GridView1.DataSource =query.ExecuteDataSet();
ExecuteReader 方法返回一个DataReader
GridView1.DataSource =query.ExecuteReader();
ExecuteScalar 返回一个单一值
Label1.Text =query.ExecuteScalar().ToString();
Ordering
排序可以通过设置 query 的 OrderBy 属性为升序或者降序来对 query 的查询结果进行排序。当然,这种情况下需要提供一个列名作为参数。
query.OrderBy =SubSonic.OrderBy.Asc(Product.Columns.ProductName);
或者
query.OrderBy =SubSonic.OrderBy.Desc(Product.Columns.ProductName);
很不幸的是,我们现在还没有一种根据多行的结果排序的方法。
Filtering
列
在默认情况下,query 将会返回查询结果的所有行。如果只想要得到过滤查询结果某几列的结果,可以将 SelectList 属性设置为用逗号间隔的列名的形式。
query.SelectList =Product.Columns.ProductName + ", " +
Product.Columns.SupplierID;
行
默认是,query 同样也返回查询的所有行。有几种方式可以让 query 只返回其中的部分行。最简单定的方式是通过设置 Top 属性,来限制只返回顶部的几行。
query.Top = "10";
(注意,此处的参数是 string 形式,而非 int 形式)
可以通过使用 AddBetweenAnd 方法来限制查询结果中某列的值在某个日期的范围之内。需要的参数是一个列名,起始和截止日期。该方法可以被多次调用,以限制多列的日期范围。
query.AddBetweenAnd(Order.Columns.OrderDate,new DateTime(1980, 1, 1),
DateTime.Now);
当参数并非日期类型是,可以使用下面的方法 AddBetweenValues
query.AddBetweenValues(Product.Columns.ProductName,"A", "F");
最后的一个,也是功能最强大的一个方法是 AddWhere.就像是 AddBetween 方法一样,它可以被多次调用,以形成一个完整的 Where 句型约束。AddWhere 类有几个重载的构造函数,其中最简单的一个需要的参数是一个列名和一个此列中要进行匹配的值。
query.AddWhere(Product.Columns.SupplierID,2);
此处的比较可以是一个进行比较的符号,而不一定是一个具体的匹配值。(具体的比较符号可以是空值,相等,不等,大于,大于等于,小于,小于等于,不匹配某个字符串。)
query.AddWhere(Product.Columns.SupplierID,SubSonic.Comparison.Greate
rThan, 2);
SubSonic 也支持对查询结果的分页处理,如果要进行分页,需要设置相应的 PageIndex 和PageSize 属性。
query.PageIndex = 2;
query.PageSize = 5;
Updating and Deleting
通过设置 query 对象的 QueryType 属性,可以实现插入,更新,删除数据库的命令。(你的
可选项包括 Delete, Insert, Select, Update).
query.QueryType =SubSonic.QueryType.Insert;
同时也可以多次是使用 AddUpdateSetting 方法
query.AddUpdateSetting(Product.Columns.UnitsInStock,100);
Aggregate Functions
Query 类包含了 3 个静态方法,用于集合方法的调用。如果要求得一列的平均值,要调用GetAverage 方法,将表和列名作为方法的参数出入。同时,可以加入一个可选的 Where 对象作为参数。
SubSonic.Query.GetAverage(Product.Schema.Name,Product.Columns.UnitPrice.ToString());
对于 GetCount 和 GetSum 方法,有相似的使用方法。
Commands
如果你觉得 SubSonic 的 query 类的查询能力还不能满足需求,你可以在使用现有的方法之前,通过写入一些命令来扩展这些方法的功能。(这个功能在 debug 的时候也很有用)query对象 有 四 个 命 令 可 以 被 利 用 , 他 们 是 : BuildCommand,BuildDeleteCommand,
BuildSelectCommand, BuildUpdate.这些命令都会返回一个QueryCommand 对象。GetSql方法将返回原 sql 语句。
string sql = query.GetSql();
每一个自动生成的对象同样能过通过调用下面四种方法之一:GetInsertCommand,
GetSelectCommand, GetUpdateCommand,GetDeleteCommand 来返 回 一 个QueryCommand 对象。
Stored Procedures
一些数据库的任务对于动态生成的 query 查询过于复杂。为了解决这个问题,SubSonic 提供了对存储过程的支持。每一个存储过程都会在类中生成一个对应的静态方法。而这个对应于存储过程的类就是 SPs。每一个存储过程的方法都会为存储过程的参数提供在方法中使用的一个对应的参数,同时会返回一个 StoredProcedure 对象。
SubSonic.StoredProcedure sp =SPs.CustOrderHist(customerID);
之后就可以调用生成的存储过程对象中的 Excute, ExcuteScalar, GetDataSet, GetReader方法,来执行相应的操作和获得结果。
GridView1.DataSource = sp.GetReader();
可以把上述两个步骤写到一起
GridView1.DataSource =SPs.CustOrderHist(customerID).GetReader();
可以通过设置 Command 属性来实现各种 QueryCommand 的功能。
Sacffolding
这种控制方法是为了快速的创建开发人员一级的管理页面。当托一个 control 控件到你的页面上时,你会得到一个 GridView 和 Update 控件。这个控件会出现在你的 vs 中的工具箱中,在 SubSonic 控件的列表中。使用这个控件,你只需要设置一下 TableName属性即可。
<cc1:Scaffold ID="Scaffold1"runat="server"TableName="Products"></cc1:Scaffold>
一些 可 视 化 的 格 式 的 调 整 可 以 通 过 EditTableCSSClass,EditTableItemCSSClass,
EditTableLabelCSSClass 和GridViewSkinID 属性来进行设置。通过对 DeleteConfirm 属
性的设置,可以改变删除时的确认信息。
Code Generation Templates
可以在不用改变代码的情况下,改变 SubSonic 生成代码的格式。SubSonic 是根据一个标准的文本生成类的结构的。通过增加标准文件到配置文件的模板库中,你可以改变 SubSonic 生成代码的结构。你可以到实例网站的 CodeTemplates directory 中查询这些标准文件。