一.什么是ORM?
ORM,即Object-Relational Mapping(对象关系映射),它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作实体对象的属性和方法。
二.Snake.Net中ORM的特点与概述:
Snake.Net框架是基于.Net 2.0 Framework设计的企业应用框架。对比其它ORM系统Snake.Net具有以下特色:
1. 全面支持泛型操作,对比普通的对象操作,使用泛型将使编码更方便,并且免除封箱和拆箱操作,效率更优。
2. Snake.Net通过DataSet配置映射关系(数据表、字段,关键字,外部关键字,关联关系等),对象的映射关系将通过元数据适配器转化为DataSet构架。因而可以使用多种方式进行关系映射(如DataSet Schema文件, Attribute特性以及外部定义文件等);此外还可以通过自定义的适配器进行扩展,以便于兼容一些其它的ORM系统配置。
3. 支持多种数据库系统,Snake.Net定义了标准的数据访问接口,通过定制不同的数据库适配器,Snake.Net几乎可以使用任何数据库产品。
4. 高效的持久层设计。Snake.Net可以通过配置文件设置不同的持久模式(缓存、对象池等)。
5. 增强的数据访问功能,支持EQL(Entity Query Language 实体查询语言),事务环境,数据绑定等高级应用。
Snake.Net通过定义映射关系,在业务实体和数据库之间建立了关联关系,并提供了EntityManager类可以对业务实体方便的进行CRUD和查询操作。先看一段演示代码:
namespace Snake.Enterprise
{
#region namespace
using System;
using ORM;
#endregion
#region Order
/// <summary>
/// This object represents the properties and methods of a Order.
/// </summary>
[Aggregation(typeof(OrderDetail))]
[TableMapping("Orders")]
public class Order:DataBindEntity
{
#region declare
[Association(typeof(OrderDetail), "OrderID")]
[ColumnMapping("OrderID", IsPrimaryKey=true, AutoIncrement=true)]
protected int porderID;
[ColumnMapping("CustomerID")]
protected string pcustomerID;
[ColumnMapping("EmployeeID")]
protected int pemployeeID;
protected decimal pfreight;
protected DateTime porderDate;
protected DateTime prequiredDate;
protected string pshipAddress;
protected string pshipCity;
protected string pshipCountry;
protected string pshipName;
protected DateTime pshippedDate;
protected string pshipPostalCode;
protected string pshipRegion;
protected int pshipVia;
#endregion
#region constructors
public Order(Customer customer, Employee employee):this()
{
//check for arguments
if (customer == null) throw new ArgumentNullException("customer");
if (employee == null) throw new ArgumentNullException("employee");
//set
pcustomerID = customer.CustomerID;
pemployeeID = employee.EmployeeID;
}
protected Order():base()
{
}
#endregion
#region properties
public string CustomerID{
get{return pcustomerID;}
}
public int EmployeeID{
get{return pemployeeID;}
}
[ColumnMapping("Freight")]
public decimal Freight
{
get{return pfreight;}
set{pfreight = value;}
}
[ColumnMapping("OrderDate")]
public DateTime OrderDate
{
get{return porderDate;}
set{porderDate = value;}
}
public int OrderID{
get{return porderID;}
}
[ColumnMapping("RequiredDate")]
public DateTime RequiredDate
{
get{return prequiredDate;}
set{prequiredDate = value;}
}
[ColumnMapping("ShipAddress")]
public string ShipAddress
{
get{return pshipAddress;}
set{pshipAddress = value;}
}
[ColumnMapping("ShipCity")]
public string ShipCity
{
get{return pshipCity;}
set{pshipCity = value;}
}
[ColumnMapping("ShipCountry")]
public string ShipCountry
{
get{return pshipCountry;}
set{pshipCountry = value;}
}
[ColumnMapping("ShipName")]
public string ShipName
{
get{return pshipName;}
set{pshipName = value;}
}
[ColumnMapping("ShippedDate")]
public DateTime ShippedDate
{
get{return pshippedDate;}
set{pshippedDate = value;}
}
[ColumnMapping("ShipPostalCode")]
public string ShipPostalCode
{
get{return pshipPostalCode;}
set{pshipPostalCode = value;}
}
[ColumnMapping("ShipRegion")]
public string ShipRegion
{
get{return pshipRegion;}
set{pshipRegion = value;}
}
[ColumnMapping("ShipVia")]
public int ShipVia
{
get{return pshipVia;}
set{pshipVia = value;}
}
#endregion
}
#endregion
#region OrderDetail
/// <summary>
/// This object represents the properties and methods of a OrderDetail.
/// </summary>
[TableMapping("Order Details")]
public class OrderDetail:DataBindEntity
{
#region declare
[ColumnMapping("OrderID", IsPrimaryKey=true)]
protected int porderID;
[ColumnMapping("ProductID", IsPrimaryKey=true)]
protected int pproductID;
protected float pdiscount;
protected short pquantity;
protected decimal punitPrice;
#endregion
#region constructors
public OrderDetail(Order order, Product product):this()
{
//check for arguments
if (order == null) throw new ArgumentNullException("order");
if (order == null) throw new ArgumentNullException("order");
//initialize
porderID = order.OrderID;
pproductID = product.ProductID;
}
protected OrderDetail():base()
{
}
#endregion
#region properties
public Product Product{
get{
return EntityManager.Retrieve<Product>(ProductID);
}
}
[ColumnMapping("Discount")]
public float Discount
{
get{return pdiscount;}
set{pdiscount = value;}
}
public int OrderID{
get{return porderID;}
}
public int ProductID{
get{return pproductID;}
}
[ColumnMapping("Quantity")]
public short Quantity
{
get{return pquantity;}
set{pquantity = value;}
}
[ColumnMapping("UnitPrice")]
public decimal UnitPrice
{
get{return punitPrice;}
set{punitPrice = value;}
}
#endregion
}
#endregion
}
string condition = "ShipName = 'Ernst Handel' && " +
" (Product.ProductName begin 'e' || Product.ProductName begin 'c')";
string sort = "Order.OrderDate Desc";
using(IEntityManager<Order> em = em = EntityManager.Create<Order>())
{
IDataPage page = new DataPage(3, em.GetCount(condition));
IList<Order> orders = em.Query(condition, sort, page);
//output orders
for(int i = 0; i < orders.Count; i++)
{
OutputOrder(orders[i]);
}
}
private void OutputOrder(Order order)
{
//check for arguments
if (order == null) throw new ArgumentNullException("order");
Console.WriteLine("-------- -------- -------- -------- -------- --------");
Console.WriteLine("Order:");
Console.WriteLine("\tId:\t{0}", order.OrderID);
Console.WriteLine("\tShipName:\t{0}", order.ShipName);
Console.WriteLine("\tShippedDate:\t{0}", order.ShippedDate);
//declare
EntityCollection<OrderDetail> details;
details = order.GetChildren<OrderDetail>();
if (details.Count > 0)
{
Console.WriteLine("\r\nDetail:");
Console.WriteLine("\tProductName\t\tUnitPrice\t\tQuantity\t\tDiscount");
foreach (OrderDetail detail in details.Entities)
{
Console.WriteLine("\t{0}\t\t\t{1}\t\t\t{2}\t\t\t{3}",
new object[]{
detail.Product.ProductName,
detail.UnitPrice,
detail.Quantity,
detail.Discount
});
}
}
}
运行结果:
Order:
Id: 10895
ShipName: Ernst Handel
ShippedDate: 1998-2-23 0:00:00
Detail:
ProductName UnitPrice Quantity Discount
GuaranáFantástica 4.5 110 0
Chartreuse verte 18 45 0
Camembert Pierrot 34 100 0
-------- -------- -------- -------- -------- --------
Order:
Id: 10895
ShipName: Ernst Handel
ShippedDate: 1998-2-23 0:00:00
Detail:
ProductName UnitPrice Quantity Discount
GuaranáFantástica 4.5 110 0
Chartreuse verte 18 45 0
Camembert Pierrot 34 100 0
-------- -------- -------- -------- -------- --------
Order:
Id: 11072
ShipName: Ernst Handel
ShippedDate: 0001-1-1 8:00:00
Detail:
ProductName UnitPrice Quantity Discount
Chang 19 8 0
Jack's New England Clam Chowder 9.65 40 0
Valkoinen suklaa 16.25 22 0
Wimmers gute Semmelkn?
-------- -------- -------- -------- -------- --------
Order:
Id: 10895
ShipName: Ernst Handel
ShippedDate: 1998-2-23 0:00:00
Detail:
ProductName UnitPrice Quantity Discount
GuaranáFantástica 4.5 110 0
Chartreuse verte 18 45 0
Boston Crab Meat 18.4 91 0
Camembert Pierrot 34 100 0
-------- -------- -------- -------- -------- --------
Order:
Id: 10895
ShipName: Ernst Handel
ShippedDate: 1998-2-23 0:00:00
Detail:
ProductName UnitPrice Quantity Discount
GuaranáFantástica 4.5 110 0
Chartreuse verte 18 45 0