C# 3.0入门(二)

Select 操作

先给关注dlinq的朋友们道歉,最近工作实在忙,没有时间来写blog。从本节开始,我们讲dlinq语法咯。我们先从select子句讲起。看下面的例子。

    var q  =
        from c 
in  db.Customers
        select c.ContactName;

这是一个最简单的dlinq查询语句,查询得到联系人的名字。在这里,我需要提醒下大家的是,像这个语句只是个声明,dlinq并没有真正把数据取出来,只有当你需要该数据的时候,它才会帮你去取,这就是延迟加载(deferred loading)。如果,你想在声明的时候就希望dlinq帮你取到数据,你可以使用ToList() 或ToArray()方法。如上例。

        var q  =  (from c  in  db.Customers
                 select c.ContactName).ToArray();
        var q  =  (from c  in  db.Customers
                 select c.ContactName).ToList();

在这里,我还要提醒大家一点。dlinq返回的结果集是对象的集合,不是数据的。
 在dlinq执行的时候,它会先将上面的标准查询转换成dlinq的API(也有人叫级连方法),比如,下面语句

            var q  =
                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语句中,另一个难点是匿名类。比如列子

            var q  =
                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来创建对象。比如,有类

     public   class  Person
    {
        
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,然后根据数据初始化对象。匿名类还有另外一种形式。

            var q  =
                from e 
in  db.Employees
                select 
new  {Name  =  e.FirstName  +   "   "   +  e.LastName, Phone  =  e.HomePhone};
这种形式和第一种不同的是,编译器会重命名property的名字。当然也可以把两种形式组合起来。
            var q  =
                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操作
最简单的

,            var q  =
                from c 
in  db.Customers
                select c.ContactName;

匿名类的

,            var q  =
                from c 
in  db.Customers
                select 
new  {c.ContactName, c.Phone};
,            var q  =
                from e 
in  db.Employees
                select 
new  {Name  =  e.FirstName  +   "   "   +  e.LastName, Phone  =  e.HomePhone};
,            var q  =
                from p 
in  db.Products
                select 
new  {p.ProductID, HalfPrice  =  p.UnitPrice  /   2 };

条件的

            var q  =
                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形式的:

            var q  =
                from e 
in  db.Employees                
                select 
new  Name {FirstName  =  e.FirstName, LastName  =  e.LastName};

只所以是name type的,是因为Name类是已经定义好的,也就是说,你可以用这种方式,返回你需要类型的对象集.
shaped形式的:

            var q  =
                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形式的:

            var q  =
                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形式的:

            var q  =  (
                from c 
in  db.Customers
                select c.City )
                .Distinct();

该形式,筛选该字段中不相同的值。会被翻译为
select distinct city from customers

where操作:
最简单的

,            var q  =
                from c 
in  db.Customers
                where c.City 
==   " London "
                select c;

,            var q  =
                from e 
in  db.Employees
                where e.HireDate 
>=   new  DateTime( 1994 1 1 )
                select e;

或与关系的where条件

,            var q  =
                from p 
in  db.Products
                where p.UnitsInStock 
<=  p.ReorderLevel  &&   ! p.Discontinued
                select p;
,            var q  =
                from p 
in  db.Products
                where p.UnitPrice 
>  10m  ||  p.Discontinued
                select p;
,            var q  =
                db.Products.Where(p
=> p.UnitPrice  >  10m).Where(p => p.Discontinued);

在上例中,1和2语句先被翻译成类似3语句的形式,再被翻译成sql语句,送回数据服务器。他们基本上一样的。
欠套在first操作中的where条件:
first操作,其实质就是在sql语句前,加了一个top 1.

,            Customer cust  =  db.Customers.First(c  =>  c.CustomerID  ==   " BONAP " );
            Order ord  =  db.Orders.First(o  =>  o.Freight  >   10.00M );

第一个例子,是筛选customerid为"BONAP"的客户,第二个筛选订单运费大于10的订单。First操作必须用这种级连的形式。比如

Shipper shipper  =  db.Shippers.First();

也可以把linq的expression和级连的形式混合使用,比如第一个例子,加入first操作,

            var q  =
                (from c 
in  db.Customers
                where c.City 
==   " London "
                select c).First();

如果加入first操作,其返回是一个具体的对象,而不是一个集合。如果first操作没有条件,它只是简单的在sql语句中添加top 1,如果有条件,它在翻译时,就会加入条件语句。

OrderBy操作

本节讲orderby操作.我突然在想这么一个问题,读者会T-SQL吗?要是不知道,那我写的是不是太简单了呢?做个调查哦,不知道的举手.
OrderBy操作
简单的,按雇用日期排序,默认为升序

            var q  =
                from e 
in  db.Employees
                orderby e.HireDate
                select e;

带where条件的,shipcity为london的。

            var q  =
                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的,按价格降序。

            var q  =
                from p 
in  db.Products
                orderby p.UnitPrice descending
                select p;

ThenBy的和ThenByDescending,也就是按多个列进行排序,第一个列子是先按city,city相同的再按contactname排序,第二个例子中,第二序列为降序。

ThenBy:
            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;

对这两个句子解释下。

对于ThenBy操作,其级连形式为:
       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要放在最后。

对于降序的,用相应的降序操作符替换即刻。

        var q  =  db.Customers.OrderByDescending(c  =>  c.City).ThenByDescending(c  =>  c.ContactName).ToList();

需要说明的是,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接口

         #region  IComparable Members

        
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>

         #region  IComparable<Customers> Members

        
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>

         #region  IComparable<OrderDetails> Members

        
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了。因为工作的变动,还要赶期限,没有时间关注这里了。

先发布一则消息。Orcas Beta1, 这个才是beta1,可以到 http://www.microsoft.com/downloads/details.aspx?FamilyID=f10fb5df-e369-4db4-b9a7-845dbf793368&DisplayLang=en 下载。5月1号的版本。最早4月19号就出来过一个,只是没有在意。还有一个 http://www.microsoft.com/downloads/details.aspx?FamilyID=36b6609e-6f3d-40f4-8c7d-ad111679d8dc&DisplayLang=en 。 一个是self-extracting 版本的,一个是Virtual PC version的。不知道什么区别。没有装过。
本节舍去原来的计划,而改讲映射工具。在入门三一文中,我们提到了sqlmetal这个工具。 http://www.cnblogs.com/126/archive/2006/09/06/492332.html sqlmetal的功能是将数据库的信息抽提出来,生成映射代码。Orcas还有另外一个工具,就是O/R Designer.
先讲sqlmetal. 自上次的版本后,sqlmetal,又增加了一些新的功能。比如,支持SQLCE版本的Sql Server, 支持直接输入connection string, 等等。 这是sqlmetal 的帮助信息,是不是比上次多了很多?

 



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. 如图所示:

弹出item对话框,category中选择data,然后选择Linq to Sql Class, 如图所示:

选择添加。这样,你的工程就多了一个O/R Desiger项目。在菜单View->Sever Explore 打开Sever Explore,添加一个Data Connection, 如图所示:

后,填写数据库服务器,用户名,密码和数据库名。如果,你没有,你可以使用Sql Express 版本。添加之后的效果,如图所示:

打开刚才添加的DataClasses1.dbml 文件,将Sever Explore中的Customer 表或view拖入Designer中来,如图所示:


也可以将Store procedure 和 User define function 拖进来,会在方法面板上形成方法。如图所示:

 
如果,两个表之间有关系,OR Designer可以显示它们的关系,将Order表和 OderDetail表拖入 如图所示:

打开DataClasses1. Designer.cs 文件,你就可以看到OR Designer给你产生的映射代码了。

 


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
        
        
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
        
        
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(thisnew 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
        
        
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(thisnew PropertyChangedEventArgs(propertyName));
            }

        }

    }

 


本节介绍了O/R Designer的基本用法,下节讲一些比较高级的用法。O/R Designer相对与sqlmetal的好处就可以设计类的继承关系(下节再讲),而sqlmetal 相对于O/R Designer是可以一次性抽提所有表的信息,快速便捷。而且sqlmetal支持一些O/R Designer无法支持的信息提取。
其Customer类,必须从IComparable继承,代码如下,
  public partial class Customers : System.Data.Linq.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged,IComparable
Icomparable接口的具体实现如下:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值