LINQ to SQL 入门






4.33/5 (9投票s)
对 C# 3.0 LINQ to SQL 技术的一次入门性探讨。
引言
LINQ 的一个流行变体是 LINQ to SQL,它借鉴了 LINQ 的概念,并将它们扩展到使用 SQL Server 数据库中的数据集合。LINQ to SQL 增加了额外的概念、对象和方法,不仅用于从数据库检索数据集,还用于插入、更新和删除数据。我将在本文中向您展示基础知识。本文介绍了一系列将数据从 SQL Server 数据库检索并显示在控制台窗口中的步骤,因此假定您具备 LINQ 语法的基本知识。目的是展示如何使用对象关系设计器创建数据上下文的基本工作流程,然后如何检索数据并将其显示在屏幕上。
为了开发此应用程序,我使用了 Visual Studio 2008 和 SQL Management Studio 2005,并使用了 2005 版的 Adventure Works LT 数据库。可以通过从 CodePlex.com 下载来安装此数据库。默认情况下,它将安装在 \Program Files\Microsoft SQL Server\MSQL.1\MSQL\90\Data 目录中。如果打开 SQL Management Studio,可以右键单击数据库文件夹并选择“附加”,然后在此处找到该目录并将其添加到数据库。之后,启动 Microsoft Visual Studio 2008(或 2005),然后使用服务器资源管理器向此数据库添加新连接。此时,启动一个 Visual C# 控制台应用程序项目,并将其命名为 LinqToSql。创建后,转到“添加新项”并选择“添加 LINQ to SQL 类”。将 .dbml 文件命名为 AdventureWorks.dbml。此文件的创建将打开一个名为对象关系设计器 (ORD) 的设计器界面。我们使用此对象关系设计器来创建数据上下文。因此,我们将 Customer (Sales LT) 表拖放到该设计器上,得到以下结果
请注意 Customer 表的这些属性
一些解释
对象关系设计器的目的是允许您建模映射到数据库以及从数据库映射的类。我们拖放了 Customer 表,这创建了一个 Customer
实体类。LINQ to SQL 允许您使用任何类来表示数据,只要用适当的属性对其进行装饰即可。下面是一个简单的示例
[Table]
public class Customer
{
[Column(IsPrimaryKey=true)]
public int ID;
[Column]
public string Name;
}
System.Data.Linq.Mapping
命名空间中的 [Table]
属性告诉 LINQ to SQL 此类型的对象代表数据库表中的一行。默认情况下,它假定表名与类名匹配;如果不是这种情况,您可以如下指定表名
[Table(Name="SalesLT.Customer")]
//(in our example)
用 [Table]
属性装饰的类在 LINQ to SQL 中称为实体。要使其有用,其结构必须与数据库表非常接近(或完全匹配),使其成为一个低级构造。[Column]
属性标记一个映射到表中列的字段或属性。您可以在定义公共字段的同时定义公共属性和私有字段。这允许您在属性访问器中编写验证逻辑。下面是(通过将 Customer 表拖放到设计器表面创建的)部分类文件。它将说明其中一些操作
#pragma warning disable 1591
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="AdventureWorksLT")]
public partial class AdventureWorksDataContext : System.Data.Linq.DataContext
{
private static System.Data.Linq.Mapping.MappingSource
mappingSource = new AttributeMappingSource();
#region Extensibility Method Definitions
partial void OnCreated();
partial void InsertCustomer(Customer instance);
partial void UpdateCustomer(Customer instance);
partial void DeleteCustomer(Customer instance);
#endregion
public AdventureWorksDataContext() :
base(global::LinqToSql.Properties.Settings.
Default.AdventureWorksLTConnectionString, mappingSource)
{
OnCreated();
}
public AdventureWorksDataContext(string connection) :
base(connection, mappingSource)
{
OnCreated();
}
public AdventureWorksDataContext(System.Data.IDbConnection connection) :
base(connection, mappingSource)
{
OnCreated();
}
public AdventureWorksDataContext(string connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public AdventureWorksDataContext(System.Data.IDbConnection connection,
System.Data.Linq.Mapping.MappingSource mappingSource) :
base(connection, mappingSource)
{
OnCreated();
}
public System.Data.Linq.Table<Customer><customer> Customers
{
get
{
return this.GetTable<customer>();
}
}
}
[Table(Name="SalesLT.Customer")]
public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs =
new PropertyChangingEventArgs(String.Empty);
private int _CustomerID;
private bool _NameStyle;
private string _Title;
private string _FirstName;
private string _MiddleName;
private string _LastName;
private string _Suffix;
private string _CompanyName;
private string _SalesPerson;
private string _EmailAddress;
private string _Phone;
private string _PasswordHash;
private string _PasswordSalt;
private System.Guid _rowguid;
private System.DateTime _ModifiedDate;
#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnCustomerIDChanging(int value);
partial void OnCustomerIDChanged();
partial void OnNameStyleChanging(bool value);
partial void OnNameStyleChanged();
partial void OnTitleChanging(string value);
partial void OnTitleChanged();
partial void OnFirstNameChanging(string value);
partial void OnFirstNameChanged();
partial void OnMiddleNameChanging(string value);
partial void OnMiddleNameChanged();
partial void OnLastNameChanging(string value);
partial void OnLastNameChanged();
partial void OnSuffixChanging(string value);
partial void OnSuffixChanged();
partial void OnCompanyNameChanging(string value);
partial void OnCompanyNameChanged();
partial void OnSalesPersonChanging(string value);
partial void OnSalesPersonChanged();
partial void OnEmailAddressChanging(string value);
partial void OnEmailAddressChanged();
partial void OnPhoneChanging(string value);
partial void OnPhoneChanged();
partial void OnPasswordHashChanging(string value);
partial void OnPasswordHashChanged();
partial void OnPasswordSaltChanging(string value);
partial void OnPasswordSaltChanged();
partial void OnrowguidChanging(System.Guid value);
partial void OnrowguidChanged();
partial void OnModifiedDateChanging(System.DateTime value);
partial void OnModifiedDateChanged();
#endregion
public Customer()
{
OnCreated();
}
[Column(Storage="_CustomerID", AutoSync=AutoSync.OnInsert,
DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int 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="_NameStyle", DbType="Bit NOT NULL")]
public bool NameStyle
{
get
{
return this._NameStyle;
}
set
{
if ((this._NameStyle != value))
{
this.OnNameStyleChanging(value);
this.SendPropertyChanging();
this._NameStyle = value;
this.SendPropertyChanged("NameStyle");
this.OnNameStyleChanged();
}
}
}
[Column(Storage="_Title", DbType="NVarChar(8)")]
public string Title
{
get
{
return this._Title;
}
set
{
if ((this._Title != value))
{
this.OnTitleChanging(value);
this.SendPropertyChanging();
this._Title = value;
this.SendPropertyChanged("Title");
this.OnTitleChanged();
}
}
}
[Column(Storage="_FirstName",
DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public string FirstName
{
get
{
return this._FirstName;
}
set
{
if ((this._FirstName != value))
{
this.OnFirstNameChanging(value);
this.SendPropertyChanging();
this._FirstName = value;
this.SendPropertyChanged("FirstName");
this.OnFirstNameChanged();
}
}
}
[Column(Storage="_MiddleName", DbType="NVarChar(50)")]
public string MiddleName
{
get
{
return this._MiddleName;
}
set
{
if ((this._MiddleName != value))
{
this.OnMiddleNameChanging(value);
this.SendPropertyChanging();
this._MiddleName = value;
this.SendPropertyChanged("MiddleName");
this.OnMiddleNameChanged();
}
}
}
[Column(Storage="_LastName",
DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
public string LastName
{
get
{
return this._LastName;
}
set
{
if ((this._LastName != value))
{
this.OnLastNameChanging(value);
this.SendPropertyChanging();
this._LastName = value;
this.SendPropertyChanged("LastName");
this.OnLastNameChanged();
}
}
}
[Column(Storage="_Suffix", DbType="NVarChar(10)")]
public string Suffix
{
get
{
return this._Suffix;
}
set
{
if ((this._Suffix != value))
{
this.OnSuffixChanging(value);
this.SendPropertyChanging();
this._Suffix = value;
this.SendPropertyChanged("Suffix");
this.OnSuffixChanged();
}
}
}
[Column(Storage="_CompanyName", DbType="NVarChar(128)")]
public string CompanyName
{
get
{
return this._CompanyName;
}
set
{
if ((this._CompanyName != value))
{
this.OnCompanyNameChanging(value);
this.SendPropertyChanging();
this._CompanyName = value;
this.SendPropertyChanged("CompanyName");
this.OnCompanyNameChanged();
}
}
}
[Column(Storage="_SalesPerson", DbType="NVarChar(256)")]
public string SalesPerson
{
get
{
return this._SalesPerson;
}
set
{
if ((this._SalesPerson != value))
{
this.OnSalesPersonChanging(value);
this.SendPropertyChanging();
this._SalesPerson = value;
this.SendPropertyChanged("SalesPerson");
this.OnSalesPersonChanged();
}
}
}
[Column(Storage="_EmailAddress", DbType="NVarChar(50)")]
public string EmailAddress
{
get
{
return this._EmailAddress;
}
set
{
if ((this._EmailAddress != value))
{
this.OnEmailAddressChanging(value);
this.SendPropertyChanging();
this._EmailAddress = value;
this.SendPropertyChanged("EmailAddress");
this.OnEmailAddressChanged();
}
}
}
[Column(Storage="_Phone", DbType="NVarChar(25)")]
public string Phone
{
get
{
return this._Phone;
}
set
{
if ((this._Phone != value))
{
this.OnPhoneChanging(value);
this.SendPropertyChanging();
this._Phone = value;
this.SendPropertyChanged("Phone");
this.OnPhoneChanged();
}
}
}
[Column(Storage="_PasswordHash",
DbType="VarChar(128) NOT NULL", CanBeNull=false)]
public string PasswordHash
{
get
{
return this._PasswordHash;
}
set
{
if ((this._PasswordHash != value))
{
this.OnPasswordHashChanging(value);
this.SendPropertyChanging();
this._PasswordHash = value;
this.SendPropertyChanged("PasswordHash");
this.OnPasswordHashChanged();
}
}
}
[Column(Storage="_PasswordSalt",
DbType="VarChar(10) NOT NULL", CanBeNull=false)]
public string PasswordSalt
{
get
{
return this._PasswordSalt;
}
set
{
if ((this._PasswordSalt != value))
{
this.OnPasswordSaltChanging(value);
this.SendPropertyChanging();
this._PasswordSalt = value;
this.SendPropertyChanged("PasswordSalt");
this.OnPasswordSaltChanged();
}
}
}
[Column(Storage="_rowguid",
DbType="UniqueIdentifier NOT NULL")]
public System.Guid rowguid
{
get
{
return this._rowguid;
}
set
{
if ((this._rowguid != value))
{
this.OnrowguidChanging(value);
this.SendPropertyChanging();
this._rowguid = value;
this.SendPropertyChanged("rowguid");
this.OnrowguidChanged();
}
}
}
[Column(Storage="_ModifiedDate", DbType="DateTime NOT NULL")]
public System.DateTime ModifiedDate
{
get
{
return this._ModifiedDate;
}
set
{
if ((this._ModifiedDate != value))
{
this.OnModifiedDateChanging(value);
this.SendPropertyChanging();
this._ModifiedDate = value;
this.SendPropertyChanged("ModifiedDate");
this.OnModifiedDateChanged();
}
}
}
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));
}
}
}
#pragma warning restore 1591
当我们把表拖放到设计器表面时,我们创建了一个对象模型。输出被称为数据上下文,它提供了对该数据模型的访问。当我们把 Customer 表拖放到 ORD 时,就创建了一个数据上下文,在该数据上下文中,创建了一个类型为 Customer
的子类
public System.Data.Linq.Table<Customer> Customers
{
get
{
return this.GetTable<customer>();
}
}
也就是说,拖放操作在数据上下文(AdventureWorksDataContext
)中创建了一个 Customers
(复数)类。同样,像 Customer
类这样的类被称为实体类。实体类的实例被称为实体。实体类映射到数据库中的表。继续向下滚动 *.dbml.cs 文件,注意所有公共和私有属性。Customers
类是 Customer 表的实体类;它正在创建您的数据层。它将数据库表的数据与应用程序中创建的实体类进行一对一的转换。数据库列和类属性之间存在一对一的映射。数据上下文是一个工厂对象,当要求枚举列表时,它会检查内存中是否已有实例。如果有,它将提供一个实体类的实例。如果没有,它将查询数据库,为检索到的每一行创建一个实体实例,然后提供您所请求的那个。一旦您请求下一个实体实例(例如,下一个客户),数据上下文就会重复这一系列事件。
此外,实体类只是数据结构,通常与数据库表定义一对一映射,并代表单个数据行。当我们查看此查询时
var myQuery = from c in myContext.Customers
select c;
LINQ to SQL 运行时知道如何将该表达式或创建的查询转换为 T-SQL。此外,它知道如何将 T-SQL 转换为实体类。这里是包含查询的文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class Program
{
static void Main(string[] args)
{
AdventureWorksDataContext myContext = new AdventureWorksDataContext();
var myQuery = from c in myContext.Customers
select c;
foreach (var c in myQuery)
{
Console.WriteLine(c.LastName);
}
Console.ReadLine();
}
}
如上面的代码所示,一旦定义了实体类,就可以通过实例化 DataContext
对象然后在其上调用 GetTable
来开始查询。诚然,这只是对 C# 3.0 的 LINQ to SQL 技术的一个非常基础的介绍。本文旨在帮助初学者入门,不能替代任何关于此主题的专业书籍。这里是执行后的输出视图