如何創建新模塊 DotNetNuke 6 & Entity Framework Code First


博客園原文地址 : 如何創建新模塊 DotNetNuke 6 & Entity Framework Code First

Soleil 索引 :

第一部分: 開發新模塊 – DNN 6

第二部分: 模塊里使用EF Code First

第一部分:開發新模塊 - DNN6


Étoile 如果你還不知道DotNetNuke是什么的話,請訪問 www.dotnetnuke.com

Étoile 如果你還不知道如何在本地安裝DNN 6, 請猛戳 http://codeciel.blogspot.fr/2012/03/how-to-install-dotnetnuke-6-on-local.html

Arc-en-ciel 如果你想要知道如何開發一個你自己的DNN6模塊,那么這篇文章就是你需要的。


  • 步驟1:通過DNN6 Host創建desktop module和module definition

從數據庫的角度出發,這一步會把新模塊的相關信息存入數據庫,讓DNN可以識別,這樣你就可以把這個模塊加入任意頁面。如果你仔細看了DNN數據庫的結構后,你會發現有很多和模塊(Module)相關的表 - dbo.DesktopModules, dbo.Modules, dbo.ModuleDefinitions, dbo.TabModules, dbo.PortalDesktopModules. 這兒不會細講這些表的用途,如果可以的話,有機會我會專門為此寫一篇博客。

所以,現在你只要按照下面的步驟就可以創建一個屬於你的DNN模塊 :

  - 用host賬戶登入你的DNN6網站

  - 點擊Host頁面,再進入Extensions頁面

  - 單擊Manage按鈕, 選擇Create New Module,你將會看到(如Figure 1所示):

提示: 如果你找不到Manage按鈕,請確認你的頁面模式(通常在右上角可以看見)是Edit而不是View或Layout。

1

Figure 1 : 創建模塊

  - 填好這些文本框后。(最后把"Add Test Page ?"打上勾,以簡化步驟)

  - 單擊“Create Module”, 然后你就可以看見新的模塊已經出現在了“TestEFCodeFirstPage”頁面上(如Figure 2 所示)了

2

Figure 2 : 新頁面里包含了新模塊

 

  • 步驟2:把新模塊與VS項目聯系起來

  - 現在打開VS2010,創建新項目,如Figure 3 所示。

提示:值得注意的事,項目的名字必須與module的名字相同,即“EFCodeFirst”,開始的時候你可以把這個項目保存到任何位置,因為一旦完成創建之后,我們會把這個文件夾移動到<網站根目錄>/DesktopModules里,合並這倆個文件夾。

3

Figure 3 : 創建新vs2010項目

  - 再次用VS2010打開“EFCodeFirst.csproj”. 因為我們還需要配置這個項目,來讓它可以順利的在DNN6下編譯和運行。

  - 點擊項目屬性,然后進入到Compiler頁面,修改輸出路徑為<網站根目錄>\bin\

  - 如果你Site的運行環境是.net framework version 2.0.50727.5448的話,請在IIS里修改Site的application pool為ASP.NET V4.0。因為EF Code First是需要.net 4.0的。

  - 添加Dotnetnuke.dll引用,它可以在<網站根目錄>\bin\下找到。需要注意的是在屬性里將copy local設置為false。

提示:上面這種添加Dotnetnuke.dll引用的方法不是企業開發常用的,或者說是應該避免的才比較正確。因為Dotnetnuke不斷在更新,為了保證團隊開發時,Dotnetnuke.dll引用都是同一個版本,我們通常會固定一個穩定的版本來開發。具體操作是:存放指定版本Dotnetnuke.dll的文件夾是共享的,所有的dnn引用都是指向這個文件夾的。

  - 重命名web.config文件為web.config.old,因為在網站的根目錄已經有了一個web.config。

  - 刪除EFView.ascx文件

  - 添加一個新文件,文件類型是Web User Control,還是命名為“EFView.ascx ”,以便DNN能識別。

  - 打開文件EFView.ascx, 我們隨便寫點東西進去,比如 : “This is my first dnn6 module”

  - 打開文件EFView.ascx.cs,將它的基類換成PortalModuleBase,保存並編譯這個項目

  - 刷新頁面http://dnn614/TestEFCodeFirstPage.aspx,你將會看到如Figure 4所示 :

4

Figure 4 : 測試頁面和行模塊


好了,看到這里你就應該知道如何創建一個DNN6模塊了。在這個模塊里,你可以根據需求,隨意開發。下面的第二部分就是,在一個DNN模塊里使用Entity Framework Code First進行實戰開發。

 

 

 

  

第二部分 : DNN模塊里使用EF Code First


Pouce levé 這部分是基於這篇文章: Introduction to Entity Framework Code First


  • 步驟 3* : Entity Framework 簡介

在我直接進入正題之前,我想先介紹一下EF。EF是一個.NET平台下的ORM框架,個人覺得做的很不錯,之前還接觸過另外倆款在.NET平台下的ORM - LLBLGen Pro和NHibernate。LLBLGen Pro自從收費之后,功能也越來越強大,用起來也挺順手的,之所以沒有繼續用的原因很簡單:我現在這個客戶公司,不想花錢買它的licence。NHibernate是從Java版的Hibernate移植過來的,就好比Lucene.NET與Lucene的關系一樣,不同的是Lucene.NET早早就進Apache的孵化器了,而NHibernate的生命力還很強大。我沒有用NHibernate的原因也很簡單,被它的配置文件驚嚇住了。比較這三款的優缺點不是這里的重點,每個人的習慣和思考方式不一樣,所以喜好自然不同,選一款自己用的順手又順心的ORM就可以了。下面開始介紹EF的三種使用方法 :

EF在4.0的時候只提供倆種與實體交互的方法,即數據庫優先模型優先。前一種情況下,你在開發你的應用前開始設計數據庫。然后你可以用VS自帶的實體數據模型設計工具來設計一個虛擬模型,操作很簡單:直接從數據庫把表拖拽到設計器中(如Figure 5所示)。后一種情況下,我們先用實體數據模型設計工具來手工設計模型(如Figure 6所示),然后指定數據庫的連接。但不管是前面哪種情況,你都要使用實體數據模型設計器來生成你的數據模型對象。

 

2-1

Figure 5 : 數據庫優先

 

2-2

Figure 6 : 模型優先

 

EF在4.1中引入一種新的模式來生成模型對象 : 代碼優先(Code First)。在代碼優先這種方式里,你不會遇到任何設計器。先全部用.NET Framework來搭建對象類,然后用一些特定屬性和相關技術來生成EF數據模型。(如Figure 7一樣)


2-3

Figure 7 : 代碼優先


上面大致講了一下這三種方法,如果你感覺有點混淆,靜下心來,仔細看Figure 8,我相信你肯定會清楚不少。在我們這個模塊中,我們使用的是最后一種。


2-4

Figure 8 : EF與實體交互的方式


第二部分的目的不僅僅是完成我們的模塊,而是一步一步的,讓大家弄清楚使用EF Code First的全部過程。接下來,在開發模塊,你將處理一個用來表示博客帖子的數據模型,實際上,數據是駐留在SQL Server里一個名叫BlogPosts表中的。通過使用模型對象,你能夠從表中讀寫數據。


  • 步驟 3 :  創建模型

假設我們的數據模型是用來儲存博客帖子和博客貼分類的。根據三層架構的思想,我們應該另外創建一個project來專門開發數據模型 :在與“EFCodeFirst”項目同一個solution里創建Library類型的新項目,命名為“EFCodeFirstLib”。這個類庫項目里將會包括倆個模型對象,即BlogPost和Category。他們的模型代碼如下展示 :

提示: EFCodeFirstLib項目的文件夾應該放在<網站根文件夾>/DesktopModules/, 並且其編譯路徑應該是<網站根文件夾>/bin/.

public class BlogPost
{
  public Guid Id { get; set; }
  public string Title { get; set; }
  public string Content { get; set; }
  public DateTime PublishDate { get; set; }
  public virtual Category Category { get; set; }
}

public class Category
{
  public Guid Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<BlogPost> BlogPosts { get; set; }
}

在BlogPost類中,定義了五個屬性: Id, Title, Content, PublishDate 和 Category。注意里面的Category是外鍵。Category類有三個屬性:Id, Name 和 BlogPosts。其中的BlogPosts 是一個屬性集合,因為可以有很多個博客帖子屬於同一個category。需要記住的是,默認情況下,表示主鍵的屬性類型應該是int或Guid。當然,你可以用一些attributes定制主鍵。我們將在后面討論。


  • 步驟4 : 創建Data Context

現在模型對象都已經創建好了,讓我們開始創建一個Data Context,通過它可以讓你查詢和處理實體數據,另外,它的基類是DbContext類。下面就是我們在模塊中要使用的Data Context:

public partial class BlogContext : DbContext
{
  public BlogContext():base("BlogDb")
  {
  }

  public DbSet<BlogPost> BlogPosts { get; set; }
  public DbSet<Category> Categories { get; set; }
}

BlogContext類繼承了DbContext類。在它的構造函數中,調用了基類的構造器並且傳遞了所需的數據庫名稱。當你首次運行應用時,將會為你用這個名字創建數據庫。如果不傳遞這個名稱,默認創建數據庫的名字將會是DbContext類的fully qualified name。在我們這個例子中就是“EFCodeFirstLib.BlogContext”。

BlogContext類定義了倆個公共屬性,即BlogPosts和Categories。這些屬性的類型是DbSet。DbSet類代表了一個實體集(從數據庫角度,就是一個數據庫的表),可以執行CRUD(創建,讀取,更新,刪除)操作


  • 步驟5 : 測試數據庫的生成(可選)

我們現在可以測試我們已經寫的代碼了,當然你也可以選擇跳過這一步。

首先在EFCodeFirst項目的“EFView.ascx”中添加一個按鈕(button),並且生成相應的按鈕點擊事件方法。加入我們剛剛創建的EFCodeFirstLib項目的引用。


Figure 9 : 測試頁面


然后在按鈕點擊事件方法中寫入以下代碼:

using (var db = new BlogContext())
{
  Guid id = Guid.NewGuid();
  var cat = new Category { Id = id, Name = "ASP.NET" };
  var post = new BlogPost { Title="Title1", Content="Hello World!", PublishDate=new DateTime(2011,1,1), Category=cat};
  db.Categories.Add(cat);
  db.BlogPosts.Add(post);
  int i = db.SaveChanges();
}

上面的代碼創建了一個BlogContext實例,接着創建了Category和BlogPost類的各自實例。把新創建的實體實例加入到DbSets里面,最后調用SaveChanges()方法。 SaveChanges()方法將持久化加入的實體數據,也就是把實體數據寫入數據庫相應的表中,並且返回此次操作執行的記錄數。

現在我們編譯這倆個項目,在瀏覽器中打開http://dnn614/TestEFCodeFirstPage.aspx. 點擊頁面中的按鈕。 因為我們是第一次運行並點擊按鈕,EF將會在SQL Express里創建新的數據庫和表。庫名是BlogDb,因為我們在DataContext的構造里已經指出了;倆個表名分別是BlogPosts和Categories。


Sans titre1

Figure 11: SQLExpress里創建的數據庫和表

 

值得注意的是BlogPosts和Categories表里的Id列被設定為主鍵, 同樣BlogPosts表中,有一名叫Category_Id的外鍵被定義。

 

  • 步驟6 : 每次運行(點擊按鈕)時重新創建數據庫

在測試時,你也許想要在每次運行應用時都創建或重新創建數據庫,以便初始化運行環境。同時也想在創建數據庫的時候加入一些測試數據。當你修改了你的實體代碼時,因為數據庫的表也會相應的改變, 數據庫也應該重新創建。默認情況下,EF只會在你首次運行時創建數據庫,之后應用會一直操作這同一個數據庫。這當然不是我們想要的,因為我們的實體代碼會隨着需求的變更而修改或增加,為了改變這種默認行為,你需要在代碼里創建一個database initializer,並且繼承DropCreateDatabaseAlways類。如名字暗示的那樣,DropCreateDatabaseAlways類總是會重新創建數據庫。下面的代碼就是我們自己的BlogContextInitializer :

提示:你也可以繼承DropCreateDatabaseIfModelChanges類,它只會在Model改變的時候,重新創建數據庫。

public class BlogContextInitializer : DropCreateDatabaseAlways<BlogContext>
{
  protected override void Seed(BlogContext context)
  {
    Category cat1 = new Category { Id=Guid.NewGuid(), Name=".NET Framework" };
    Category cat2 = new Category { Id = Guid.NewGuid(), Name = "SQL Server" };
    Category cat3 = new Category { Id = Guid.NewGuid(), Name = "jQuery" };
    context.Categories.Add(cat1);
    context.Categories.Add(cat2);
    context.Categories.Add(cat3);
    context.SaveChanges();
  }
}

BlogContextInitializer 繼承了DropCreateDatabaseAlways 基類,並且重寫了Seed()方法,方法里寫入了一些往數據庫里添加樣本數據的代碼:添加了三個categories。一旦完成了initializer,你需要添加以下代碼到按鈕點擊事件方法里去:

protected void Button1_Click(object sender, EventArgs e)
{
  Database.SetInitializer<BlogContext>(new BlogContextInitializer());
  ...
  ...
}

現在你就會發現每次點擊按鈕時,數據庫都會重新創建,並且填充樣本數據到Categories表里。

 

  • 步驟7 : 在Code First里使用已有的數據庫

上面的代碼里,你允許EF自己創建數據。但在許多情況下,你會想要用已經存在的數據庫而不是創建一個新的。又因為我們在DNN里使用EF Code First,所以在任何情況下都不可能全部重新創建DNN使用的數據庫(DNN614)。我們不得不使用其它的數據庫(比如DNN614_BlogDb)。如何讓Code First知道我們想要使用那個數據庫呢?只需要在web.config的Connection String里指明就可以了:

<connectionStrings>
  <add name="SiteSqlServer" connectionString="Data Source=(local)\LEGAL;Initial Catalog=DNN614;User ID=login614;Password=xxx" providerName="System.Data.SqlClient" />
  <add name="BlogDb" connectionString="Data Source=(local)\LEGAL;Initial Catalog=DNN614_BlogDb;User ID=lgfr;Password=xxx" providerName="System.Data.SqlClient"/>
</connectionStrings>


Sans titre

Figure 12 : 指明已有的數據庫

 

需要注意的地方是,我們在<connectionStrings>里添加的數據庫連接字符串的名字,必須和我們在DataContext構造器里指明的一樣(“BlogDb”)。

如果你在DataContext沒有指明,那么那個數據庫連接字符串的名字就必須和DataContext類名一樣(“BlogContext”)。

為了讓大家更清楚Code First選擇數據庫連接字符串的流程,我們用這個例子再解釋一遍 :

  •   情況一:在DataContext中(BlogContext)指明了名字“BlogDb”

      EF首先會在configuration文件里查找是否有名字為“BlogDb”的數據庫連接字符串。

      如果有,EF就會使用這個。如果沒有,EF就會在本地的SQL Express中創建一個名為“BlogDb”的新數據庫。

  •   情況二:沒有在DataContext中(BlogContext)指明

      EF首先也會在configuration文件里查找名為“BlogContext ”的數據庫連接字符串。

      如果找到,EF就是使用;否則EF就會在SQL Express里創建一個名為“EFCodeFirstLib.BlogContext”的新數據庫。其中EFCodeFirstLib是BlogContext的命名空間。

 

  • 步驟8 : 使用Data Annotations來標明數據表和鍵的信息

上面的例子中,當創建實體對象對應的數據庫和表時,EF使用的是默認的約定。我們也可以用一些data annotations來定制EF的行為。例如下面代碼所示,我們添加了一些data annotations屬性來標明表名([Table]),主鍵([Key]) 和外鍵([ForeignKey])信息。

[Table("BlogPosts")]
public class BlogPost
{
  [Key]
  public Guid Id { get; set; }
  public string Title { get; set; }
  public string Content { get; set; }
  public DateTime PublishDate { get; set; }
  [ForeignKey("Category")]
  public Guid CategoryId { get; set; }
  public virtual Category Category { get; set; }
}

[Table("Categories")]
public class Category
{
  [Key]
  public Guid Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<BlogPost> BlogPosts { get; set; }
}

 

  • 總結 :

Entity Framework Code First允許我們直接在代碼使用EF特性,比如未經任何實體數據模型設計。這種方式下,全部使用C#類來創建實體對象,需要定義一個繼承了DbContext類的DataContext類,同時可以使用data annotation屬性顯式地標明相關信息。默認時,當應用第一次運行時,EF會在SQL Express里創建新的數據庫;我們可以通過創建自己的數據庫初始化策略(Database Initializer)來改變這種默認行為。也可以使用已經存在的數據庫,只需在configuration文件里標明了數據庫連接字符串。 

Code First相對與其他兩種方式來說,有很大的靈活性。但我覺得在DNN中不太適合使用,因為我不是特別能接受一個DNN網站同時有倆個數據庫,維護起立不方便。所以,在現實項目中,我經常使用的方式是Database First。

最后友情提供一下本例中的DNN模塊安裝包和源代碼:安裝包  源代碼Profitez-le et je vous souhaite un très bon weekend !!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM