程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 走進Linq-Linq to SQL How do I(3)

走進Linq-Linq to SQL How do I(3)

編輯:關於.NET

NHibernate是使用XML作為映射的配置文件,Caslte中的ActiveRecord(底層 還是使用NHibernate)是使用Attribute的方式做映射配置。一個是非侵入的,一 個是侵入的。有人喜歡用XML做配置,說這樣靈活,修改配置無需重新編譯,有 人喜歡使用Attribute的配置方式,說這樣可維護性好,可以得到編譯期的檢查 。

不過在Linq裡,這一切都不是問題。Linq to SQL這幾種方式都支持, 而且走的更遠。

純Attribute方式配置

XMl文件的配置方式

使用SqlMetal命令行工具生成配置代碼

使用Visual Studio的設 計器生成映射配置代碼

純Attribute方式配置

前面幾篇我們都是使用 這種Attribute的方式的,在Linq to SQL的第一篇我就介紹了,這些映射的 Attribute都存在於System.Data.Linq.Mapping命名空間下。在前面我們已經出 現了TableAttribute,ColumnAttribute, AssociationAttribute。實際上還有 DataBaseAttribute,ProviderAttribute,FunctionAttribute。本篇後面的內 容將在不同的地方對他們做全面的介紹。

Table

Table特性是加在 類上面的,不能重復的加,也不能繼承。Table,顧名思義,就是用來定義類和 數據庫表之間的映射的,Table是映射定義的關鍵點,如果沒有給一個類加上 Table特性,那麼即使這個類裡面的屬性或字段加上了Column也是無效的,實際 上,前面幾篇中的例子,如果沒有給映射類加Table特性在運行時會拋出一個異 常:System.InvalidOperationException,說你的類沒有映射為一個Table。 Table特性只有一個屬性Name,用於在你的類名和數據庫表名不同的時候來定義。

Column

Column特性就復雜得多了。不過可喜的是,這些屬性的命 名都很好,只要見到名字了,基本上就能把意思給猜出來了。

AutoSync

AutoSync:自動同步。這個屬性是一個枚舉類型:

public enum AutoSync
{
Default,
Always,
Never,
OnInsert,
OnUpdate
}

這個屬性的意 思是,執行insert和update操作後,這個類的屬性如何和數據庫表的那個被修改 列的字段進行同步。

AutoSync. Default,自動選擇,默認就是這個,一 般是如果該列在數據庫裡有默認值,Column的IsDbGenerated屬性標記為true的 時候則同步。

AutoSync. Always,總是進行同步

AutoSync.Never ,從來不同步

AutoSync.OnInsert,在執行插入操作後同步,像我們博客 園的那個例子,Blog的Id是主鍵,自增的,插入數據庫的時候我們並不提供,而 是數據庫自動生成的,那這個時候我們的類插入以後這個Id如何同步呢?

AutoSync. OnUpdate,在更新的時候同步

實際上我們可以看看, 這個AutoSync是如何影響Linq to SQL的行為的(打開前面我們曾經建的那個博客 園的例子,如果你沒有創建一個強烈建議你回到前幾篇按照那裡的步驟新建)

我們執行一下對Post的插入:

DataContext dbContext = new DataContext(ConfigurationManager.ConnectionStrings ["CnBlogs"].ConnectionString);
dbContext.Log = Console.Out;
var post = new Post {
BlogId = 1,
Title = "Linq to SQL How do I(3)",
Body = "廢話一堆 ",
};
dbContext.GetTable<Post>().InsertOnSubmit (post);
dbContext.SubmitChanges();

看看生成的SQL代碼 :

在insert的代碼下面,我們還會看到一個select的代碼,將postid和 createdate給查詢回來,但我們並沒有執行查詢操作啊,原來這就是AutoSync在 使壞,在默認的時候IsDbGenerated為true的列是被會查出來返回的。為了檢查 一下說的是不是對的,我將Post的Title屬性修改一下:

[Column (AutoSync=AutoSync.Always)]public string Title { get; set; }

然後再執行上面 插入代碼,看看生成的SQL又將如何呢:

呵呵,生成的select語句也將Title給查回來了。

現在應該明 白這個AutoSync的意義了吧,你可以自己一一試驗。

CanBeNull

這個屬性可以指定對應的數據庫表的列是否允許是null的,如果這個列不能為 null,那你給這個屬性賦個null的時候,是要觸發異常的。不過要記住,null並 不代表是一個空字符串或者零,關於null的更多內容,你可以參見園子Anytao的 佳作。

DbType

如果你想使用DataContext的CreateDataBase方法 從映射類創建數據庫表,那麼最好指定這個,這樣你就可以明確的指定出你的這 個列在數據庫表中的DbType是啥,不然Linq to SQL會從屬性的類型推斷DbType ,這有可能不怎麼適合,比如這個string類型:

[Column (DbType="NVarchar(50) not null")] public string Title { get; set; }

在這裡我們是不是發現了,我們還可以從映射類創建數據 庫,都說ORM是以O為主,可我們實踐的時候總是先建立數據庫,然後根據數據庫 創建Object,那這不是ROM了麼,從這裡的信息表示,你可以先設計好Domain Object,並建立好Object之間的關系,最後使用CreateDataBase方法來創建數據 庫表。關於CreateDataBase更多的信息在後面我會更進一步的說明的。

Expression

我只能說Linq to SQL做的太周到了,連這個都考慮 了。Expression用來表示一個計算列,什麼意思?意思是這個屬性是數據庫表的 列通過計算獲取的,比如,假如我們數據庫裡有一列price存儲的是美元,可是 取出來的時候我們要求用人民幣表示:

[Column (Expression="price * 6")] public float Price { get; set; }

上面的例子只是用來說明Expression這個屬性的用途,而這個例 子的做法實在是不可取,對於美元轉人民幣這種匯率問題,匯率是時刻波動的, 所以這樣硬編碼,實在是糟糕的很,各位讀了以後BS一下,一笑而過吧。

IsDbGenerated

從名字上就可以看出來了,這個表明這個屬性的 值是數據庫產生的,不需要我們的程序賦值,比如這個自增的列,比如這個有默 認值的列(時間,我們可以用SQL getdate()函數設置值,而無需我們在程序裡指 定)

IsPrimaryKey

是主鍵嗎?如果是就要指定這個屬性了,如果 你的主鍵是多個列組成的,那麼就在多個屬性上加吧。關於主鍵,在後面還會進 一步介紹。

IsVersion和UpdateCheck

這兩個在這裡就不說了,後 面會有大篇幅的介紹的。這個Column特性是從抽象特性Data繼承來的,從這個特 性繼承了兩個屬性:

Name

這個是當你的屬性名字和這個列名不一 致的時候指定列名用的。

Storage

有的時候啊,你的屬性裡的set 裡面應用了復雜的業務邏輯,而Linq to SQL在將值從數據庫取出,然後賦值給 這個屬性的時候,默認是要使用這個set的,這個時候在這種情況下(從數據庫取 值賦給類的屬性),你並不想執行這個set裡面的邏輯,想把這個值直接給屬性背 後的那個私有字段:

private float _price;
/// <summary>
/// 由於某些原因,當從數據庫取值給Price屬性的時候
/// 你不想給這個值乘以20
/// </summary>
[Column (Storage="_price")]
public float Price
{
   get { return _price; }
  set{_price = _price * 20;
}

Association

這個特性是用來建立實體之間關系的。在前面的 例子裡我們看到了:

/// <summary>
/// 一個博客有 零篇或多篇文章,
/// </summary>
[Association (ThisKey="Id",OtherKey = "BlogId")]
public EntitySet<Post> Posts { get; set; }

Association有兩 個最重要的屬性就是ThisKey和OtherKey

ThisKey用來標識和別的對象關 聯的鍵,如果沒有指明就用本類屬性上標識有IsPrimaryKey的了。OtherKey用來 定義關聯的類的鍵,如果沒有指定就用關聯的那個類的標識列了。

Association特性也是從Data特性繼承來的,也有Name和Storage屬性。 Storage屬性和Column是一樣的,這裡的Name屬性是CreateDataBase利用映射類 動態創建數據庫的時候建立關系用的,這個Name就是關系名。關於Association 的更多信息你還是參看上一篇文章。

我們用的最多的就是上面三個 Attribute了,不過Linq to SQL還提供好幾個Attribute,我想這個放在後面相 應的地方再做介紹。

XML文件的配置方式

有心的你也許發現了, DataContext類有好幾個重載的構造函數,我們常用的是:

DataContext (string fileOrConnectionString)

還有一個:

DataContext (string fileOrConnectionString,MappingSource mapping)

這個 MappingSource是干嗎的呢?

在System.Data.Linq.Mapping命名空間下, 你會發現這樣的個關系:

看到它的兩個子類的名稱你也許就會猜出十之八九了吧,我們前面所 使用的就是AttributeMappingSouce映射,除此之外還可以使用XML作為映射的配 置文件哦,從上面的圖看,XmlMappingSource還有幾個靜態的方法,他們可以以 各種形式的Xml數據源來構建XmlMappingSource實例:

XmlMappingSource mapping = XmlMappingSource.FromXml(File.ReadAllText (@“e:"cnblogs"map.xml”)); DataContext dbContext = new DataContext(connectionString,mapping);

用這種方式構建 DataContext對象我們就可以使用Xml作映射了。

我們就來看看這個XML映 射文件的格式:

<?xml version="1.0" encoding="utf-16"?>
<Database Name="Cnblogs" xmlns="http://schemas.microsoft.com/linqtosql/mapping/2007"& gt;
<Table Name="posts">
  <Type Name="Yuyijq.Linq.Cnblogs.Domain.Post">
    <Column Name="postid" Member="Id" IsPrimaryKey="true" IsDbGenerated="true" />
   <Column Name="blogid" Member="BlogId" />
   <Column Name="title" Member="Title" />
   <Column Name="body" Member="Body" />
    <Column Name="createdate" Member="CreateDate" IsDbGenerated="true"/>
  </Type>
</Table>
</Database>

大家可以看到,這 個文件有一個根元素DataBase,這個對應著Attribute裡的DataBaseAttribute, 每個DataBase元素可以包含有一個或多個Table,每個Table元素有一個Type元素 ,這個是用來指定這個Table和哪個實體類對應的。一個Type元素有一個或多個 Column和Association元素。從上面的Xml中可以看出,它的用法和Attribute的 一樣,只是多了一個Member,這個是用來指定實體類的屬性的,其余的意義和 Attribute的是一樣的。

基本上每個ORM工具都提供了代碼生成工具,我 想如果沒有代碼生成使用ORM的工作量也是不小的,靠手動的去寫實體類和映射 文件純粹是個體力活。Linq to SQL也不例外,為你提供了強大的工具。

使用SqlMetal命令行工具生成配置代碼

SqlMetal是個命令行工具,這樣你就 可以很好的將其與MSBuild等進行集成,以達到自動化的目的。只要寫個批處理 文件,映射的東東都自動生成了。

關於SqlMetal的用法你只要在命令行 裡輸入SqlMetal /?就可以了,這裡就不做過多的介紹。

值得注意的是: 我們寫的實體類往往希望他們能通過WebService或WCF傳遞,那麼就要求它們是 可系列化的,為此微軟為SqlMetal工具准備了這個開關:

/serialization:,option有兩個值:None和Unidirectional,默認是 None。

使用Visual Studio的設計器生成映射配置代碼

畢竟整天伴隨 著我們的是VS,所以還是來個可視化的工具比較過瘾。

你只要在你的項 目當中新建一個LINQ to SQL Classes類型的新項,然後從服務器浏覽器裡把表 拖到設計界面上,然後用工具欄裡面的工具,連接好各個表之間的關系就OK了。

VS會為我們生成三個文件:一個以dbml為後綴的文件(其實這個文件就是 個xml格式的文件,它和剛才只用xml作映射配置的文件格式是類似的)一個C#代 碼文件,注意到這個代碼文件是個局部類,該類和dbml文件共同編譯成一個類, 這個和asp.net裡面的aspx和它的後台代碼使用的方式類似。還有一個是以 layout為後綴名的,這個文件是設計器使用的,用來存儲設計器中各表在界面上 的位置,和我們的程序無關。

關於可視化的設計器的使用這裡也不做介 紹了,自己動動手,然後看看生成的幾個文件裡到底是什麼東西,加上前面對手 動操作的詳細講解,我想理解這個將是很容易的事情。

後記

本來想用 三篇的長度將如何使用部分,看來還是不行。這篇文章比較長,但東西不是很多 。

下一篇將是How do I的最後一篇,將對DataContext,做Update和 Delete時RowVersion、Linq to SQL中的事務和延遲計算、延遲加載等內容做詳 細介紹。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved