Select 操作
先给关注dlinq的朋友们道歉,最近工作实在忙,没有时间来写blog。从本节开始,我们讲dlinq语法咯。我们先从select子句讲起。看下面的例子。
from c in db.Customers
select c.ContactName;
这是一个最简单的dlinq查询语句,查询得到联系人的名字。在这里,我需要提醒下大家的是,像这个语句只是个声明,dlinq并没有真正把数据取出来,只有当你需要该数据的时候,它才会帮你去取,这就是延迟加载(deferred loading)。如果,你想在声明的时候就希望dlinq帮你取到数据,你可以使用ToList() 或ToArray()方法。如上例。
select c.ContactName).ToArray();
select c.ContactName).ToList();
在这里,我还要提醒大家一点。dlinq返回的结果集是对象的集合,不是数据的。
在dlinq执行的时候,它会先将上面的标准查询转换成dlinq的API(也有人叫级连方法),比如,下面语句
from c in db.Customers
where c.City == " London "
select c;
就会先被转化成 var q = db.Customers.Where(c=>c.City== "London").Select(c=>c); 也就是说,这两个语句是等价的。而后,dlinq会解析影射文件,根据dlinq的query语句,自动产生sql语句,并把sql送到sql server服务器,根据返回的数据集,创建相应的对象。在这里,你可能会对c=>c感到非常陌生。这是Lambda表达式(expression),你可以理解c为结果集里的任一对象,这对象的类型是和你结果集里元素类型是一致的 。这里理解起来可能困难。我们一起来理解下数据即是对象的概念。我相信这会帮我们理解Lambda表达式。
在dlinq之前,在java领域有Hibernate,在net领域有NHibernate技术,来实现object/relational 持久和查询服务。dlinq其实质上,是在吸收了众多技术的基础上,比他们更加强大的工具。数据即对象的含义有两层。第一,数据结构(表结构)即是类。可以描述为Table Schema--Class。第二,表里的数据即是变量,描述为Data--object(variable)。那么,我们在来理解Lambda表达式可能就容易些。刚才我们已经说了,var q = db.Customers.Where(c=>c.City== "London").Select(c=>c);将会返回Customers对象的集合,也就说,这个集合的每个元素就是一个Customer。Lambda表达式是对c# 2.0中的anonymous methods(匿名方法)的扩展。它更加简化匿名方法的实现形式。这里的c是一种隐式的声明,编译器会自动推断它的实际类型,也可以显示声明,比如, var q = db.Customers.Where((Customer c) => c.City == "London").ToList(); Lambda表达式用=>符号跟随一个表达式,这个表达式,需要返回一个类型,其实质就是一个方法返回一个类型。它只是更加简洁的匿名方法。然后,where等操作符用它返回的这个类型做为参数。关于Lambda表达式的具体实现,我会在进阶部分详细讲解。这里不再赘述。
有一点要提醒大家的是,标准的查询语句,必须是select语句在最后,而级连表达式,各种操作符的位置并不是很重要。比如var q = db.Customers.Where(c=>c.City== "London").Select(c=>c); 可以写成var q = db.Customers.Select(c=>c).Where(c=>c.City== "London");它们两个是一样的,但是,标准查询就不可以换位子,select语句必须在最后。虽然在级连表达式,各种操作符的位置并不是很重要,但是他们还是有区别的。特别是在使用匿名类后,区别很明显。但万变不离其宗,我们只要记住,下一个操作符总是在上一个操作符所筛选的数据集的基础上进行筛选。这点,我会在以后的blog中,更加详细的说明。
在select语句中,另一个难点是匿名类。比如列子
from c in db.Customers
select new {c.ContactName, c.Phone};
其实不光在select操作中有匿名类,其他操作中也有。让我们一起来理解下匿名类。上面的语句与
var q = db.Customers.Select(c=>new {c,ContactName,c.Phone});是等价的。匿名类是c# 3.0中新出现的特性。其实质是编译器根据用户定义,自动产生一个匿名的类,帮用户实现临时变量的储存。注意,是临时变量。大量使用匿名类会使程序可读性降低。匿名类还依赖于另外一个特性,就是在c# 3.0可以支持根据property来创建对象。比如,有类
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
以前,我们只可以用构造函数来创建其对象,现在在3.0中支持用property来创建,即,可以用
var d = new Person { Name = "s" }; 来创建对象。在这里,你可能还对var类型产生疑问。你可能以为c#3.0和javascript一样是弱类型的。其实var并不是c#3.0的类型,它是编译器的关键字,编译器根据实际变量的返回类型,自动推断类型。那么var c = null; 是无法编译通过,因为编译不知道null代表那个类型。所以,c#3.0还是强类型的。
现在3.0可以支持用property来创建对象了,那么就有了匿名类的出现。比如,var d = new { Name = "s" };编译器自动产生一个有property叫做Name的匿名类,然后按这个类型分配内存,并初始化对象。在这个地方,还有个问题,比如,var d = new { "s" };是编译不通过的。因为,编译器不知道匿名类中的property的名字。但是,如果, string c = "d"; var d = new { c}; 则是可以通过编译的。编译器会创建一个叫做匿名类带有叫c的property。
在dlinq中,比如new {c,ContactName,c.Phone});这里出现ContactName和Phone都是我们在影射文件中定义的和表中字段相对应的property。编译器在取会数据并创建对象时,会创建一个匿名类,这个类有两个属性,为ContactName和Phone,然后根据数据初始化对象。匿名类还有另外一种形式。
from e in db.Employees
select new {Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone};
from p in db.Products
select new {p.ProductID, HalfPrice = p.UnitPrice / 2 };
第一个属性的名字不会变,第二个会被重新命名。
好,就先讲这几个,下节我会介绍几个更复杂的用法。
从本节开始,本文正式更名为C#3.0入门系列。先发布一则消息,VS2007 Beta版本已经发布咯,下载地址:
http://www.microsoft.com/downloads/details.aspx?FamilyID=1FF0B35D-0C4A-40B4-915A-5331E11C39E6&displaylang=en
大家快去下载呀,我也好和大家一起体验该版本最新功能呀。
dlinq也更名为linq to sql.本文也跟着做相应变化,稍候,我会去更新前面的文章。我们先接着讲linq的语法。
Select操作
最简单的
from c in db.Customers
select c.ContactName;
匿名类的
from c in db.Customers
select new {c.ContactName, c.Phone};
2 , var q =
from e in db.Employees
select new {Name = e.FirstName + " " + e.LastName, Phone = e.HomePhone};
3 , var q =
from p in db.Products
select new {p.ProductID, HalfPrice = p.UnitPrice / 2 };
条件的
from p in db.Products
select new {p.ProductName, Availability = p.UnitsInStock - p.UnitsOnOrder < 0 ? " Out Of Stock " : " In Stock " };
这种条件的会被翻译成sql中{case when condition then else}的。
name type形式的:
from e in db.Employees
select new Name {FirstName = e.FirstName, LastName = e.LastName};
只所以是name type的,是因为Name类是已经定义好的,也就是说,你可以用这种方式,返回你需要类型的对象集.
shaped形式的:
from c in db.Customers
select new {
c.CustomerID,
CompanyInfo = new {c.CompanyName, c.City, c.Country},
ContactInfo = new {c.ContactName, c.ContactTitle}
};
该形式,其select操作使用了匿名对象,而这个匿名对象中,其属性也是个匿名对象。
nested形式的:
from o in db.Orders
select new {
o.OrderID,
DiscountedProducts =
from od in o.OrderDetails
where od.Discount > 0.0
select od,
FreeShippingDiscount = o.Freight
};
其返回的对象集中的每个对象DiscountedProducts属性中,又包含一个小的集合。也就是每个对象也是一个集合类。
Distinct形式的:
from c in db.Customers
select c.City )
.Distinct();
该形式,筛选该字段中不相同的值。会被翻译为
select distinct city from customers
where操作:
最简单的
from c in db.Customers
where c.City == " London "
select c;
2 , var q =
from e in db.Employees
where e.HireDate >= new DateTime( 1994 , 1 , 1 )
select e;
或与关系的where条件
from p in db.Products
where p.UnitsInStock <= p.ReorderLevel && ! p.Discontinued
select p;
2 , var q =
from p in db.Products
where p.UnitPrice > 10m || p.Discontinued
select p;
3 , var q =
db.Products.Where(p => p.UnitPrice > 10m).Where(p => p.Discontinued);
在上例中,1和2语句先被翻译成类似3语句的形式,再被翻译成sql语句,送回数据服务器。他们基本上一样的。
欠套在first操作中的where条件:
first操作,其实质就是在sql语句前,加了一个top 1.
2 Order ord = db.Orders.First(o => o.Freight > 10.00M );
第一个例子,是筛选customerid为"BONAP"的客户,第二个筛选订单运费大于10的订单。First操作必须用这种级连的形式。比如
也可以把linq的expression和级连的形式混合使用,比如第一个例子,加入first操作,
(from c in db.Customers
where c.City == " London "
select c).First();
如果加入first操作,其返回是一个具体的对象,而不是一个集合。如果first操作没有条件,它只是简单的在sql语句中添加top 1,如果有条件,它在翻译时,就会加入条件语句。
OrderBy操作
本节讲orderby操作.我突然在想这么一个问题,读者会T-SQL吗?要是不知道,那我写的是不是太简单了呢?做个调查哦,不知道的举手.
OrderBy操作
简单的,按雇用日期排序,默认为升序
from e in db.Employees
orderby e.HireDate
select e;
带where条件的,shipcity为london的。
from o in db.Orders
where o.ShipCity == " London "
orderby o.Freight
select o;
或
var q =
from o in db.Orders
orderby o.Freight
where o.ShipCity == " London "
select o;
在这里where和orderby的顺序并不重要。而在T-SQL中,where和orderby有严格的位置限制。
OrderByDescending的,按价格降序。
from p in db.Products
orderby p.UnitPrice descending
select p;
ThenBy的和ThenByDescending,也就是按多个列进行排序,第一个列子是先按city,city相同的再按contactname排序,第二个例子中,第二序列为降序。
var q =
from c in db.Customers
orderby c.City, c.ContactName
select c;
ThenByDescending:
var q =
from o in db.Orders
where o.EmployeeID == 1
orderby o.ShipCountry, o.Freight descending
select o;
对这两个句子解释下。
var q = db.Customers.OrderBy(c => c.City).ThenBy(c => c.ContactName).ToList();
因为T - SQL中,并没有ThenBy语句,其依然翻译为OrderBy
所以,也可以用下面语句来表达
var q = db.Customers.OrderBy(c => c.ContactName).OrderBy(c => c.City).ToList();
所要注意的是,是两个orderby的顺序,多个orderby操作时,级连方式是按逆序.即先按city排时,city要放在最后。
对于降序的,用相应的降序操作符替换即刻。
需要说明的是,orderby操作,不支持按type排序,也不支持匿名类。
比如 var q = db.Customers.OrderBy(c => c).ToList();和
var q = db.Customers.OrderBy(c => new {c.City,c.ContactName}).ToList();
会被抛出异常。但是,既然提了,大家在这个问题就不会犯错误,常见的错误是前面的操作有匿名类,再跟orderby时,比较的是类别。比如
var q = db.Customers.Select(c => new { c.City, c.Address }).OrderBy(c => c).ToList();
如果你想使用OrderBy(c => c),其前提条件是,前面步骤中,所产生的对象的类别必须为C#语言的基本类型。比如
var q = db.Customers.Select(c=>c.City).OrderBy(c => c).ToList();
city为string类型。
还有一点需要说明的时,linq和dlinq在orderby操作中,稍微有一点区别。linq支持按type排序,但是,需要你自己去实现IComparable接口。
比如语句:var q = db.Customers.ToList().OrderBy(c => c).ToList();
第一个ToList()会把数据库中所有数据取出,放到内存中,以后所有的操作全部是对内存操作。后面的所有操作均为linq操作,不是dlinq。(这一点,我前面的文章中讲过)如果,你想用按客户进行排序,你必须在Customer类中,实现IComparable接口
public int CompareTo( object obj)
{
return this ._CustomerID.CompareTo(((Customers)obj).CustomerID);
// throw new Exception("The method or operation is not implemented.");
}
#endregion
Orderby操作,会自动调用该接口的方法,实现按类别排序。如果,你的映射文件中没有实现该接口,系统会抛出异常。
你也可以使用generic,如下,
public partial class Customers : System.Data.Linq.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged,IComparable<Customers>
public int CompareTo(Customers other)
{
return this .CustomerID.CompareTo(other.CustomerID);
// throw new Exception("The method or operation is not implemented.");
}
#endregion
好处就是你无须把object强制转化为customer类。
我们再来定义个,先按订单号排序,相同订单按产品号排序的。
public partial class OrderDetails : System.Data.Linq.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged,IComparable<OrderDetails>
public int CompareTo(OrderDetails other)
{
int k = this ._OrderID - other.OrderID;
if (k == 0 )
{
k = this ._ProductID - other.ProductID;
}
return k;
// throw new Exception("The method or operation is not implemented.");
}
好了,更多的功能,等待大家自己去实现。下次讲Groupby操作。
OR工具介绍
不得不再次给关注dlinq的朋友道歉了。好久都没有更新blog了。因为工作的变动,还要赶期限,没有时间关注这里了。
Microsoft (R) Database Mapping Generator 2008 Beta 2 version 1.00.20612
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
SqlMetal [options] [<input file>]
Generates code and mapping for the LINQ to SQL component of the .NET framework. SqlMetal can:
- Generate source code and mapping attributes or a mapping file from a database.
- Generate an intermediate dbml file for customization from the database.
- Generate code and mapping attributes or mapping file from a dbml file.
Options:
/server:<name> Database server name.
/database:<name> Database catalog on server.
/user:<name> Login user ID (default: use Windows Authentication).
/password:<password> Login password (default: use Windows Authentication).
/conn:<connection string> Database connection string. Cannot be used with /server, /database, /us
er or /password options.
/timeout:<seconds> Timeout value to use when SqlMetal accesses the database (default: 0 wh
ich means infinite).
/views Extract database views.
/functions Extract database functions.
/sprocs Extract stored procedures.
/dbml[:file] Output as dbml. Cannot be used with /map option.
/code[:file] Output as source code. Cannot be used with /dbml option.
/map[:file] Generate mapping file, not attributes. Cannot be used with /dbml option
.
/language:<language> Language for source code: VB or C# (default: derived from extension on code file name).
/namespace:<name> Namespace of generated code (default: no namespace).
/context:<type> Name of data context class (default: derived from database name).
/entitybase:<type> Base class of entity classes in the generated code (default: entities have no base class).
/pluralize Automatically pluralize or singularize class and member names using English language rules.
/serialization:<option> Generate serializable classes: None or Unidirectional (default: None).
/provider:<type> Provider type (default: provider is determined at run time).
<input file> May be a SqlExpress mdf file, a SqlCE sdf file, or a dbml intermediate file.
Create code from SqlServer:
SqlMetal /server:myserver /database:northwind /code:nwind.cs /namespace:nwind
Generate intermediate dbml file from SqlServer:
SqlMetal /server:myserver /database:northwind /dbml:northwind.dbml /namespace:nwind
Generate code with external mapping from dbml:
SqlMetal /code:nwind.cs /map:nwind.map northwind.dbml
Generate dbml from a SqlCE sdf file:
SqlMetal /dbml:northwind.dbml northwind.sdf
Generate dbml from SqlExpress local server:
SqlMetal /server:./sqlexpress /database:northwind /dbml:northwind.dbml
Generate dbml by using a connection string in the command line:
SqlMetal /conn:"server='myserver'; database='northwind'" /dbml:northwind.dbml
因为sqlmetal已经讲过,不再多讲,大家知道它是个命令行的工具,用来做映射数据库信息的,会使用就可以。再接着讲O/R Designer. 新建任一工程。右击工程,选择add->new item. 如图所示:
也可以将Store procedure 和 User define function 拖进来,会在方法面板上形成方法。如图所示:
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Data;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;
using System.ComponentModel;
using System;
[System.Data.Linq.Mapping.DatabaseAttribute(Name="northwind_may06ctp")]
public partial class DataClasses1DataContext : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource();
Extensibility Method Definitions#region Extensibility Method Definitions
partial void OnCreated();
partial void InsertOrder(Order instance);
partial void UpdateOrder(Order instance);
partial void DeleteOrder(Order instance);
partial void InsertOrder_Detail(Order_Detail instance);
partial void UpdateOrder_Detail(Order_Detail instance);
partial void DeleteOrder_Detail(Order_Detail instance);
#endregion
static DataClasses1DataContext()
{
}
public DataClasses1DataContext(string connection) :
base(connection, mappingSource)
{
OnCreated();
}
public DataClasses1DataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public DataClasses1DataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public DataClasses1DataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public DataClasses1DataContext() :
base(global::SqlMetalUtil.Properties.Settings.Default.northwind_may06ctpConnectionString, mappingSource)
{
OnCreated();
}
public System.Data.Linq.Table<Order> Orders
{
get
{
return this.GetTable<Order>();
}
}
public System.Data.Linq.Table<Order_Detail> Order_Details
{
get
{
return this.GetTable<Order_Detail>();
}
}
[Function(Name="dbo.CategoriesInsert")]
public int CategoriesInsert([Parameter(Name="@CategoryID", DbType="int")] System.Nullable<int> CategoryID, [Parameter(Name="@CategoryName", DbType="nvarchar")] string CategoryName, [Parameter(Name="@Description", DbType="ntext")] string Description, [Parameter(Name="@Picture", DbType="image")] byte[] Picture)
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), CategoryID, CategoryName, Description, Picture);
return ((int)(result.ReturnValue));
}
}
[Table(Name="dbo.Orders")]
public partial class Order : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _OrderID;
private string _CustomerID;
private System.Nullable<int> _EmployeeID;
private System.Nullable<System.DateTime> _OrderDate;
private System.Nullable<System.DateTime> _RequiredDate;
private System.Nullable<System.DateTime> _ShippedDate;
private System.Nullable<int> _ShipVia;
private System.Nullable<decimal> _Freight;
private string _ShipName;
private string _ShipAddress;
private string _ShipCity;
private string _ShipRegion;
private string _ShipPostalCode;
private string _ShipCountry;
private EntitySet<Order_Detail> _Order_Details;
Extensibility Method Definitions#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate();
partial void OnCreated();
partial void OnOrderIDChanging(int value);
partial void OnOrderIDChanged();
partial void OnCustomerIDChanging(string value);
partial void OnCustomerIDChanged();
partial void OnEmployeeIDChanging(System.Nullable<int> value);
partial void OnEmployeeIDChanged();
partial void OnOrderDateChanging(System.Nullable<System.DateTime> value);
partial void OnOrderDateChanged();
partial void OnRequiredDateChanging(System.Nullable<System.DateTime> value);
partial void OnRequiredDateChanged();
partial void OnShippedDateChanging(System.Nullable<System.DateTime> value);
partial void OnShippedDateChanged();
partial void OnShipViaChanging(System.Nullable<int> value);
partial void OnShipViaChanged();
partial void OnFreightChanging(System.Nullable<decimal> value);
partial void OnFreightChanged();
partial void OnShipNameChanging(string value);
partial void OnShipNameChanged();
partial void OnShipAddressChanging(string value);
partial void OnShipAddressChanged();
partial void OnShipCityChanging(string value);
partial void OnShipCityChanged();
partial void OnShipRegionChanging(string value);
partial void OnShipRegionChanged();
partial void OnShipPostalCodeChanging(string value);
partial void OnShipPostalCodeChanged();
partial void OnShipCountryChanging(string value);
partial void OnShipCountryChanged();
#endregion
public Order()
{
OnCreated();
this._Order_Details = new EntitySet<Order_Detail>(new Action<Order_Detail>(this.attach_Order_Details), new Action<Order_Detail>(this.detach_Order_Details));
}
[Column(Storage="_OrderID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int OrderID
{
get
{
return this._OrderID;
}
set
{
if ((this._OrderID != value))
{
this.OnOrderIDChanging(value);
this.SendPropertyChanging();
this._OrderID = value;
this.SendPropertyChanged("OrderID");
this.OnOrderIDChanged();
}
}
}
[Column(Storage="_CustomerID", DbType="NChar(5)")]
public string CustomerID
{
get
{
return this._CustomerID;
}
set
{
if ((this._CustomerID != value))
{
this.OnCustomerIDChanging(value);
this.SendPropertyChanging();
this._CustomerID = value;
this.SendPropertyChanged("CustomerID");
this.OnCustomerIDChanged();
}
}
}
[Column(Storage="_EmployeeID", DbType="Int")]
public System.Nullable<int> EmployeeID
{
get
{
return this._EmployeeID;
}
set
{
if ((this._EmployeeID != value))
{
this.OnEmployeeIDChanging(value);
this.SendPropertyChanging();
this._EmployeeID = value;
this.SendPropertyChanged("EmployeeID");
this.OnEmployeeIDChanged();
}
}
}
[Column(Storage="_OrderDate", DbType="DateTime")]
public System.Nullable<System.DateTime> OrderDate
{
get
{
return this._OrderDate;
}
set
{
if ((this._OrderDate != value))
{
this.OnOrderDateChanging(value);
this.SendPropertyChanging();
this._OrderDate = value;
this.SendPropertyChanged("OrderDate");
this.OnOrderDateChanged();
}
}
}
[Column(Storage="_RequiredDate", DbType="DateTime")]
public System.Nullable<System.DateTime> RequiredDate
{
get
{
return this._RequiredDate;
}
set
{
if ((this._RequiredDate != value))
{
this.OnRequiredDateChanging(value);
this.SendPropertyChanging();
this._RequiredDate = value;
this.SendPropertyChanged("RequiredDate");
this.OnRequiredDateChanged();
}
}
}
[Column(Storage="_ShippedDate", DbType="DateTime")]
public System.Nullable<System.DateTime> ShippedDate
{
get
{
return this._ShippedDate;
}
set
{
if ((this._ShippedDate != value))
{
this.OnShippedDateChanging(value);
this.SendPropertyChanging();
this._ShippedDate = value;
this.SendPropertyChanged("ShippedDate");
this.OnShippedDateChanged();
}
}
}
[Column(Storage="_ShipVia", DbType="Int")]
public System.Nullable<int> ShipVia
{
get
{
return this._ShipVia;
}
set
{
if ((this._ShipVia != value))
{
this.OnShipViaChanging(value);
this.SendPropertyChanging();
this._ShipVia = value;
this.SendPropertyChanged("ShipVia");
this.OnShipViaChanged();
}
}
}
[Column(Storage="_Freight", DbType="Money")]
public System.Nullable<decimal> Freight
{
get
{
return this._Freight;
}
set
{
if ((this._Freight != value))
{
this.OnFreightChanging(value);
this.SendPropertyChanging();
this._Freight = value;
this.SendPropertyChanged("Freight");
this.OnFreightChanged();
}
}
}
[Column(Storage="_ShipName", DbType="NVarChar(40)")]
public string ShipName
{
get
{
return this._ShipName;
}
set
{
if ((this._ShipName != value))
{
this.OnShipNameChanging(value);
this.SendPropertyChanging();
this._ShipName = value;
this.SendPropertyChanged("ShipName");
this.OnShipNameChanged();
}
}
}
[Column(Storage="_ShipAddress", DbType="NVarChar(60)")]
public string ShipAddress
{
get
{
return this._ShipAddress;
}
set
{
if ((this._ShipAddress != value))
{
this.OnShipAddressChanging(value);
this.SendPropertyChanging();
this._ShipAddress = value;
this.SendPropertyChanged("ShipAddress");
this.OnShipAddressChanged();
}
}
}
[Column(Storage="_ShipCity", DbType="NVarChar(15)")]
public string ShipCity
{
get
{
return this._ShipCity;
}
set
{
if ((this._ShipCity != value))
{
this.OnShipCityChanging(value);
this.SendPropertyChanging();
this._ShipCity = value;
this.SendPropertyChanged("ShipCity");
this.OnShipCityChanged();
}
}
}
[Column(Storage="_ShipRegion", DbType="NVarChar(15)")]
public string ShipRegion
{
get
{
return this._ShipRegion;
}
set
{
if ((this._ShipRegion != value))
{
this.OnShipRegionChanging(value);
this.SendPropertyChanging();
this._ShipRegion = value;
this.SendPropertyChanged("ShipRegion");
this.OnShipRegionChanged();
}
}
}
[Column(Storage="_ShipPostalCode", DbType="NVarChar(10)")]
public string ShipPostalCode
{
get
{
return this._ShipPostalCode;
}
set
{
if ((this._ShipPostalCode != value))
{
this.OnShipPostalCodeChanging(value);
this.SendPropertyChanging();
this._ShipPostalCode = value;
this.SendPropertyChanged("ShipPostalCode");
this.OnShipPostalCodeChanged();
}
}
}
[Column(Storage="_ShipCountry", DbType="NVarChar(15)")]
public string ShipCountry
{
get
{
return this._ShipCountry;
}
set
{
if ((this._ShipCountry != value))
{
this.OnShipCountryChanging(value);
this.SendPropertyChanging();
this._ShipCountry = value;
this.SendPropertyChanged("ShipCountry");
this.OnShipCountryChanged();
}
}
}
[Association(Name="Order_Order_Detail", Storage="_Order_Details", OtherKey="OrderID")]
public EntitySet<Order_Detail> Order_Details
{
get
{
return this._Order_Details;
}
set
{
this._Order_Details.Assign(value);
}
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}
protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void attach_Order_Details(Order_Detail entity)
{
this.SendPropertyChanging();
entity.Order = this;
this.SendPropertyChanged("Order_Details");
}
private void detach_Order_Details(Order_Detail entity)
{
this.SendPropertyChanging();
entity.Order = null;
this.SendPropertyChanged("Order_Details");
}
}
[Table(Name="dbo.[Order Details]")]
public partial class Order_Detail : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _OrderID;
private int _ProductID;
private decimal _UnitPrice;
private short _Quantity;
private float _Discount;
private EntityRef<Order> _Order;
Extensibility Method Definitions#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate();
partial void OnCreated();
partial void OnOrderIDChanging(int value);
partial void OnOrderIDChanged();
partial void OnProductIDChanging(int value);
partial void OnProductIDChanged();
partial void OnUnitPriceChanging(decimal value);
partial void OnUnitPriceChanged();
partial void OnQuantityChanging(short value);
partial void OnQuantityChanged();
partial void OnDiscountChanging(float value);
partial void OnDiscountChanged();
#endregion
public Order_Detail()
{
OnCreated();
this._Order = default(EntityRef<Order>);
}
[Column(Storage="_OrderID", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int OrderID
{
get
{
return this._OrderID;
}
set
{
if ((this._OrderID != value))
{
if (this._Order.HasLoadedOrAssignedValue)
{
throw new System.Data.Linq.ForeignKeyReferenceAlreadyHasValueException();
}
this.OnOrderIDChanging(value);
this.SendPropertyChanging();
this._OrderID = value;
this.SendPropertyChanged("OrderID");
this.OnOrderIDChanged();
}
}
}
[Column(Storage="_ProductID", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int ProductID
{
get
{
return this._ProductID;
}
set
{
if ((this._ProductID != value))
{
this.OnProductIDChanging(value);
this.SendPropertyChanging();
this._ProductID = value;
this.SendPropertyChanged("ProductID");
this.OnProductIDChanged();
}
}
}
[Column(Storage="_UnitPrice", DbType="Money NOT NULL")]
public decimal UnitPrice
{
get
{
return this._UnitPrice;
}
set
{
if ((this._UnitPrice != value))
{
this.OnUnitPriceChanging(value);
this.SendPropertyChanging();
this._UnitPrice = value;
this.SendPropertyChanged("UnitPrice");
this.OnUnitPriceChanged();
}
}
}
[Column(Storage="_Quantity", DbType="SmallInt NOT NULL")]
public short Quantity
{
get
{
return this._Quantity;
}
set
{
if ((this._Quantity != value))
{
this.OnQuantityChanging(value);
this.SendPropertyChanging();
this._Quantity = value;
this.SendPropertyChanged("Quantity");
this.OnQuantityChanged();
}
}
}
[Column(Storage="_Discount", DbType="Real NOT NULL")]
public float Discount
{
get
{
return this._Discount;
}
set
{
if ((this._Discount != value))
{
this.OnDiscountChanging(value);
this.SendPropertyChanging();
this._Discount = value;
this.SendPropertyChanged("Discount");
this.OnDiscountChanged();
}
}
}
[Association(Name="Order_Order_Detail", Storage="_Order", ThisKey="OrderID", IsForeignKey=true)]
public Order Order
{
get
{
return this._Order.Entity;
}
set
{
Order previousValue = this._Order.Entity;
if (((previousValue != value)
|| (this._Order.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._Order.Entity = null;
previousValue.Order_Details.Remove(this);
}
this._Order.Entity = value;
if ((value != null))
{
value.Order_Details.Add(this);
this._OrderID = value.OrderID;
}
else
{
this._OrderID = default(int);
}
this.SendPropertyChanged("Order");
}
}
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}
protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
本节介绍了O/R Designer的基本用法,下节讲一些比较高级的用法。O/R Designer相对与sqlmetal的好处就可以设计类的继承关系(下节再讲),而sqlmetal 相对于O/R Designer是可以一次性抽提所有表的信息,快速便捷。而且sqlmetal支持一些O/R Designer无法支持的信息提取。
public partial class Customers : System.Data.Linq.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged,IComparable
Icomparable接口的具体实现如下: