[轉]MVC實用架構設計(三)——EF-Code First(3):使用T4模板生成類似代碼

本文轉自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.htmlhtml

〇、目錄

1、前言緩存

2、工具準備架構

3、T4代碼生成預熱mvc

  (一) 單文件生成:HelloWorld.csapp

  (二) 多文件生成框架

4、生成數據層實體相關類似代碼ide

  (一) 生成準備svn

  (二) 生成實體相關類似代碼函數

  1. 生成實體映射配置類
  2. 生成實體倉儲接口
  3. 生成實體倉儲實現

5、源碼獲取工具

系列導航

1、前言

  通過前面EF的《第一篇》與《第二篇》,咱們的數據層功能已經較爲完善了,但有很多代碼類似度較高,好比負責實體映射的 EntityConfiguration,負責倉儲操做的IEntityRepository與EntityRepository。並且每添加一個實體類型,就要手動去添加一套相應的代碼,也是比較累的工做。若是能有一個根據實體類型自動生成這些類似度較高的代碼的解決方案,那將會減小大量的無聊的工做。

  VS提供的「文本模板」(俗稱T4)功能,就是一個較好的解決方案。要添加一個實體類型,只要把實體類型定義好,而後運行一下定義好的T4模板,就能夠自動生成相應的類文件。

2、工具準備

   爲了更好的使用 T4模板 功能,咱們須要給VS安裝以下兩個插件:

  • Devart T4 Editor:爲VS提供智能提示功能。
  • T4 Toolbox:在生成多文件時頗有用。

3、T4代碼生成預熱

(一) 單文件生成:HelloWorld.cs

   下面,咱們先來體驗一個最簡單的T4代碼生成功能,輸出一個最簡單的類文件。

  首先,在 GMF.Demo.Core.Data中 添加一個名爲 T4 的文件夾,用於存放生成本工程內的代碼的T4模板文件。並在其中添加一個名爲 HelloWorld.tt的「文本模板」的項。

  HelloWorld.tt定義以下:

複製代碼
 1 <#@ template debug="false" hostspecific="false" language="C#" #>
 2 <#@ assembly name="System.Core" #>
 3 <#@ import namespace="System.Linq" #>
 4 <#@ import namespace="System.Text" #>
 5 <#@ import namespace="System.Collections.Generic" #>
 6 <#@ output extension=".cs" #>
 7 using System;
 8 
 9 namespace GMF.Demo.Core.Data.T4
10 {
11     public class HelloWorld
12     {
13         private string _word;
14 
15         public HelloWorld(string word)
16         {
17             _word = word;
18         }
19     }
20 }
複製代碼

   直接保存文件(T4的生成將會在保存模板,模板失去焦點等狀況下自動觸發生成。),將會在模板的當前位置生成一個同名的類文件:

  HelloWorld.cs的內容以下:

複製代碼
 1 using System;
 2 
 3 namespace GMF.Demo.Core.Data.T4
 4 {
 5     public class HelloWorld
 6     {
 7         private string _word;
 8 
 9         public HelloWorld(string word)
10         {
11             _word = word;
12         }
13     }
14 }
複製代碼

   這樣,咱們的HelloWorld之旅就結束了,很是簡單。

(二) 多文件生成

  當前位置方案的方案只能生成以下所示的代碼:

  生成的文件會與T4模板在同一目錄中,這裏就不詳述了,能夠參考 蔣金楠 一個簡易版的T4代碼生成"框架" 。

  本項目的多文件須要生成到指定文件夾中,但又想對T4模板進行統一的管理,T4文件夾裏放置T4模板文件,但生成的映射文件EntityConfiguration將放置到文件夾Configurations中,倉儲操做的文件IEntityRepository與EntityRepository將放置到Repositories文件夾中。且生成的代碼文件應能自動的添加到解決方案中,而不是隻是在文件夾中存在。

  要實現此需求,一個簡單的辦法就是經過 T4 Toolbox 來進行生成。想了解 T4 Toolbox 的細節,能夠本身使用 ILSpy 來對 T4Toolbox.dll 文件進行反編譯來查看源代碼,若是是經過 T4 Toolbox 是經過VS的插件來安裝的,將在「C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\dca4f0lt.jdx」文件夾中(個人機器上)。下面,咱們直接進行多文件生成的演示。

  首先,添加一個名爲 HelloWorldTemplate.tt 的 T4 Toolbox 的代碼模板。

  此模板將繼承於 T4 Toolbox 的 CSharpTemplate 類:

複製代碼
 1 <#+
 2 // <copyright file="HelloWorldTemplate.tt" company="郭明鋒@中國">
 3 //  Copyright © 郭明鋒@中國. All Rights Reserved.
 4 // </copyright>
 5 
 6 public class HelloWorldTemplate : CSharpTemplate
 7 {
 8     private string _className;
 9 
10     public HelloWorldTemplate(string className)
11     {
12         _className = className;
13     }
14 
15     public override string TransformText()
16     {
17 #>
18 using System;
19 
20 namespace GMF.Demo.Core.Data.T4
21 {
22     public class <#=_className #>
23     {
24         private string _word;
25 
26         public <#=_className #>(string word)
27         {
28             _word = word;
29         }
30     }
31 }
32 <#+
33         return this.GenerationEnvironment.ToString();
34     }
35 }
36 #>
複製代碼

   模板類中定義了一個 className 參數,用於接收一個表示要生成的類名的值。全部生成類的代碼都以字符串的形式寫在重寫的 TransformText 方法中。

  再定義一個T4模板文件 HelloWorldMulti.tt,用於調用 上面定義的代碼模板進行代碼文件的生成。

複製代碼
 1 <#@ template debug="false" hostspecific="false" language="C#" #>
 2 <#@ assembly name="System.Core" #>
 3 <#@ import namespace="System.IO" #>
 4 <#@ import namespace="System.Linq" #>
 5 <#@ import namespace="System.Text" #>
 6 <#@ import namespace="System.Collections.Generic" #>
 7 <#@ include file="T4Toolbox.tt" #>
 8 <#@ include file="HelloWorldTemplate.tt" #>
 9 <#
10     string curPath = Path.GetDirectoryName(Host.TemplateFile);
11     string destPath = Path.Combine(curPath, "outPath");
12     if(!Directory.Exists(destPath))
13     {
14         Directory.CreateDirectory(destPath);
15     }
16     string[] classNames = new[]{"HelloWorld1", "HelloWorld2", "HelloWorld3"};
17     foreach(string className in classNames)
18     {
19         HelloWorldTemplate template = new HelloWorldTemplate(className);
20         string fileName = string.Format(@"{0}\{1}.cs", destPath, className);
21         template.Output.Encoding = Encoding.UTF8;
22         template.RenderToFile(fileName);
23     }
24  #>
複製代碼

  以上是整個T4模板的執行方,在執行方中,要引用全部須要用到的類庫文件,命名空間,包含的模板文件等。

  最後,文件的生成是調用 T4 Toolbox 的Template基類中定義的 RenderToFile(string filename)方法來生成各個文件的,輸入的參數爲生成文件的文件全名。在這裏,生成將以下所示:

  outPPath文件夾中生成了 HelloWorld1.cs、HelloWorld2.cs、HelloWorld3.cs 文件,而 HelloWorldMulti.tt 所在文件夾中也會生成一個空的 HelloWorldMulti.cs 類文件。

4、生成數據層實體相關類似代碼

(一) 生成準備

  咱們的生成代碼是徹底依賴於業務實體的,因此,須要有一個類來對業務實體的信息進行提取封裝。

複製代碼
 1 namespace GMF.Component.Tools.T4
 2 {
 3     /// <summary>
 4     /// T4實體模型信息類
 5     /// </summary>
 6     public class T4ModelInfo
 7     {
 8         /// <summary>
 9         /// 獲取 模型所在模塊名稱
10         /// </summary>
11         public string ModuleName { get; private set; }
12 
13         /// <summary>
14         /// 獲取 模型名稱
15         /// </summary>
16         public string Name { get; private set; }
17 
18         /// <summary>
19         /// 獲取 模型描述
20         /// </summary>
21         public string Description { get; private set; }
22 
23         public IEnumerable<PropertyInfo> Properties { get; private set; }
24 
25         public T4ModelInfo(Type modelType)
26         {
27             var @namespace = modelType.Namespace;
28             if (@namespace == null)
29             {
30                 return;
31             }
32             var index = @namespace.LastIndexOf('.') + 1;
33             ModuleName = @namespace.Substring(index, @namespace.Length - index);
34             Name = modelType.Name;
35             var descAttributes = modelType.GetCustomAttributes(typeof(DescriptionAttribute), true);
36             Description = descAttributes.Length == 1 ? ((DescriptionAttribute)descAttributes[0]).Description : Name;
37             Properties = modelType.GetProperties();
38         }
39     }
40 }
複製代碼

   另外,經過模板生成的代碼,與咱們手寫的代碼有以下幾個區別:

  1. 手寫代碼能夠自由定義,生成代碼是根據模板生成的,必然遵照模板定義的規範。
  2. 手寫代碼的修改能夠永久保存,生成代碼的修改將會在下次生成後丟失,即生成代碼不該該進行修改。

  基於以上幾個區別,我提出以下解決方案,來解決生成代碼的修改問題

  1. 經過模板生成的類應儘可能定義爲分部類(partial class),在須要進行修改及擴展的時候能夠定義另外的同名分部類來進行修改。
  2. 對於須要外部實現的功能,定義分部方法來對外提供擴展。
  3. 生成代碼的類文件命名把擴展名由「.cs」更改成「generated.cs」,以區分生成代碼與手寫代碼文件。

(二) 生成實體相關類似代碼

  1. 生成實體映射配置類

  實體映射配置類模板 EntityConfigurationTemplate.tt 定義:

複製代碼
 1 <#+
 2 // <copyright file="EntityConfigurationTemplate.tt" company="郭明鋒@中國">
 3 //  Copyright © 郭明鋒@中國. All Rights Reserved.
 4 // </copyright>
 5 
 6 public class EntityConfigurationTemplate : CSharpTemplate
 7 {
 8     private T4ModelInfo _model;
 9         
10     public EntityConfigurationTemplate(T4ModelInfo model)
11     {
12         _model = model;
13     }
14 
15     /// <summary>
16     /// 獲取 生成的文件名,根據模型名定義
17     /// </summary>
18     public string FileName
19     {
20         get
21         { 
22             return string.Format("{0}Configuration.generated.cs", _model.Name);
23         }
24     }
25 
26     public override string TransformText()
27     {
28 #>
29 //------------------------------------------------------------------------------
30 // <auto-generated>
31 //     此代碼由工具生成。
32 //     對此文件的更改可能會致使不正確的行爲,而且若是
33 //     從新生成代碼,這些更改將會丟失。
34 //        如存在本生成代碼外的新需求,請在相同命名空間下建立同名分部類實現 <#= _model.Name #>ConfigurationAppend 分部方法。
35 // </auto-generated>
36 //
37 // <copyright file="<#= _model.Name #>Configuration.generated.cs">
38 //        Copyright(c)2013 GMFCN.All rights reserved.
39 //        CLR版本:4.0.30319.239
40 //        開發組織:郭明鋒@中國
41 //        公司網站:http://www.gmfcn.net
42 //        所屬工程:GMF.Demo.Core.Data
43 //        生成時間:<#= DateTime.Now.ToString("yyyy-MM-dd HH:mm") #>
44 // </copyright>
45 //------------------------------------------------------------------------------
46 
47 using System;
48 using System.Data.Entity.ModelConfiguration;
49 using System.Data.Entity.ModelConfiguration.Configuration;
50 
51 using GMF.Component.Data;
52 using GMF.Demo.Core.Models;
53 
54 
55 namespace GMF.Demo.Core.Data.Configurations
56 {
57     /// <summary>
58     /// 實體類-數據表映射——<#= _model.Description #>
59     /// </summary>    
60     internal partial class <#= _model.Name #>Configuration : EntityTypeConfiguration<<#= _model.Name #>>, IEntityMapper
61     {
62         /// <summary>
63         /// 實體類-數據表映射構造函數——<#= _model.Description #>
64         /// </summary>
65         public <#= _model.Name #>Configuration()
66         {
67             <#= _model.Name #>ConfigurationAppend();
68         }
69         
70         /// <summary>
71         /// 額外的數據映射
72         /// </summary>
73         partial void <#= _model.Name #>ConfigurationAppend();
74         
75         /// <summary>
76         /// 將當前實體映射對象註冊到當前數據訪問上下文實體映射配置註冊器中
77         /// </summary>
78         /// <param name="configurations">實體映射配置註冊器</param>
79         public void RegistTo(ConfigurationRegistrar configurations)
80         {
81             configurations.Add(this);
82         }
83     }
84 }
85 <#+
86         return this.GenerationEnvironment.ToString();
87     }
88 }
89 #>
複製代碼

   生成模板調用方 EntityCodeScript.tt 定義

複製代碼
 1 <#@ template language="C#" debug="True" #>
 2 <#@ output extension="cs" #>
 3 <#@ Assembly Name="System.Core" #>
 4 <#@ Assembly Name="$(SolutionDir)\GMF.Component.Tools\bin\Debug\GMF.Component.Tools.dll" #>
 5 <#@ import namespace="System.IO" #>
 6 <#@ Import Namespace="System.Linq" #>
 7 <#@ Import Namespace="System.Text" #>
 8 <#@ import namespace="System.Reflection" #>
 9 <#@ Import Namespace="System.Collections.Generic" #>
10 <#@ Import Namespace="GMF.Component.Tools" #>
11 <#@ Import Namespace="GMF.Component.Tools.T4" #>
12 <#@ include file="T4Toolbox.tt" #>
13 <#@ include file="Include\EntityConfigurationTemplate.tt" #>
14 <#
15     string currentPath = Path.GetDirectoryName(Host.TemplateFile);
16     string projectPath =currentPath.Substring(0, currentPath.IndexOf(@"\T4"));
17     string solutionPath = currentPath.Substring(0, currentPath.IndexOf(@"\GMF.Demo.Core.Data"));
18 
19     string modelFile= Path.Combine(solutionPath, @"GMF.Demo.Core.Models\bin\Debug\GMF.Demo.Core.Models.dll");
20     byte[] fileData= File.ReadAllBytes(modelFile);
21     Assembly assembly = Assembly.Load(fileData);
22     IEnumerable<Type> modelTypes = assembly.GetTypes().Where(m => typeof(Entity).IsAssignableFrom(m) && !m.IsAbstract);
23     foreach(Type modelType in modelTypes)
24     {
25         T4ModelInfo model = new T4ModelInfo(modelType);
26         //實體映射類
27         EntityConfigurationTemplate config = new EntityConfigurationTemplate(model);
28         string path = string.Format(@"{0}\Configurations", projectPath);
29         config.Output.Encoding = Encoding.UTF8;
30         config.RenderToFile(Path.Combine(path, config.FileName));
31     }
32 #>
複製代碼

  調用方經過反射從業務實體程序集 GMF.Demo.Core.Models.dll 中獲取全部基類爲 Entity 的而且不是抽象類的實體類型信息,再調用模板逐個生成實體配置類文件。

  例如,生成的登陸記錄信息(LoginLog)的映射文件 LoginLogConfiguration.generated.cs 以下:

複製代碼
 1 //------------------------------------------------------------------------------
 2 // <auto-generated>
 3 //     此代碼由工具生成。
 4 //     對此文件的更改可能會致使不正確的行爲,而且若是
 5 //     從新生成代碼,這些更改將會丟失。
 6 //        如存在本生成代碼外的新需求,請在相同命名空間下建立同名分部類實現 LoginLogConfigurationAppend 分部方法。
 7 // </auto-generated>
 8 //
 9 // <copyright file="LoginLogConfiguration.generated.cs">
10 //        Copyright(c)2013 GMFCN.All rights reserved.
11 //        CLR版本:4.0.30319.239
12 //        開發組織:郭明鋒@中國
13 //        公司網站:http://www.gmfcn.net
14 //        所屬工程:GMF.Demo.Core.Data
15 //        生成時間:2013-06-16 17:45
16 // </copyright>
17 //------------------------------------------------------------------------------
18 
19 using System;
20 using System.Data.Entity.ModelConfiguration;
21 using System.Data.Entity.ModelConfiguration.Configuration;
22 
23 using GMF.Component.Data;
24 using GMF.Demo.Core.Models;
25 
26 
27 namespace GMF.Demo.Core.Data.Configurations
28 {
29     /// <summary>
30     /// 實體類-數據表映射——登陸記錄信息
31     /// </summary>    
32     internal partial class LoginLogConfiguration : EntityTypeConfiguration<LoginLog>, IEntityMapper
33     {
34         /// <summary>
35         /// 實體類-數據表映射構造函數——登陸記錄信息
36         /// </summary>
37         public LoginLogConfiguration()
38         {
39             LoginLogConfigurationAppend();
40         }
41         
42         /// <summary>
43         /// 額外的數據映射
44         /// </summary>
45         partial void LoginLogConfigurationAppend();
46         
47         /// <summary>
48         /// 將當前實體映射對象註冊到當前數據訪問上下文實體映射配置註冊器中
49         /// </summary>
50         /// <param name="configurations">實體映射配置註冊器</param>
51         public void RegistTo(ConfigurationRegistrar configurations)
52         {
53             configurations.Add(this);
54         }
55     }
56 }
複製代碼

  要配置登陸信息與用戶信息的 N:1 關係,只須要添加一個分部類 LoginLogConfiguration,並實現分類方法 LoginLogConfigurationAppend 便可。

複製代碼
 1 namespace GMF.Demo.Core.Data.Configurations
 2 {
 3     partial class LoginLogConfiguration
 4     {
 5         partial void LoginLogConfigurationAppend()
 6         {
 7             HasRequired(m => m.Member).WithMany(n => n.LoginLogs);
 8         }
 9     }
10 }
複製代碼

  2. 生成實體倉儲接口

  實體映射配置類模板 EntityConfigurationTemplate.tt 定義:

複製代碼
 1 <#+
 2 // <copyright file="IEntityRepositoryTemplate.tt" company="郭明鋒@中國">
 3 //  Copyright © 郭明鋒@中國. All Rights Reserved.
 4 // </copyright>
 5 
 6 public class IEntityRepositoryTemplate : CSharpTemplate
 7 {
 8     private T4ModelInfo _model;
 9         
10     public IEntityRepositoryTemplate(T4ModelInfo model)
11     {
12         _model = model;
13     }
14 
15     /// <summary>
16     /// 獲取 生成的文件名,根據模型名定義
17     /// </summary>
18     public string FileName
19     {
20         get
21         { 
22             return string.Format("I{0}Repository.generated.cs", _model.Name);
23         }
24     }
25 
26     public override string TransformText()
27     {
28 #>
29 //------------------------------------------------------------------------------
30 // <auto-generated>
31 //     此代碼由工具生成。
32 //     對此文件的更改可能會致使不正確的行爲,而且若是
33 //     從新生成代碼,這些更改將會丟失。
34 //       如存在本生成代碼外的新需求,請在相同命名空間下建立同名分部類進行實現。
35 // </auto-generated>
36 //
37 // <copyright file="I<#= _model.Name #>Repository.generated.cs">
38 //        Copyright(c)2013 GMFCN.All rights reserved.
39 //        CLR版本:4.0.30319.239
40 //        開發組織:郭明鋒@中國
41 //        公司網站:http://www.gmfcn.net
42 //        所屬工程:GMF.Demo.Core.Data
43 //        生成時間:<#= DateTime.Now.ToString("yyyy-MM-dd HH:mm") #>
44 // </copyright>
45 //------------------------------------------------------------------------------
46 
47 using System;
48 
49 using GMF.Component.Data;
50 using GMF.Demo.Core.Models;
51 
52 
53 namespace GMF.Demo.Core.Data.Repositories
54 {
55     /// <summary>
56     ///   數據訪問層接口——<#= _model.Description #>
57     /// </summary>
58     public partial interface I<#= _model.Name #>Repository : IRepository<<#= _model.Name #>>
59     { }
60 }
61 
62 <#+
63         return this.GenerationEnvironment.ToString();
64     }
65 }
66 #>
複製代碼

   相應的,在調用方 EntityCodeScript.tt 中添加模板調用代碼(以下 11-15 行所示):

複製代碼
 1     foreach(Type modelType in modelTypes)
 2     {
 3         T4ModelInfo model = new T4ModelInfo(modelType);
 4 
 5         //實體映射類
 6         EntityConfigurationTemplate config = new EntityConfigurationTemplate(model);
 7         string path = string.Format(@"{0}\Configurations", projectPath);
 8         config.Output.Encoding = Encoding.UTF8;
 9         config.RenderToFile(Path.Combine(path, config.FileName));
10 
11         //實體倉儲操做接口
12         IEntityRepositoryTemplate irep= new IEntityRepositoryTemplate(model);
13         path = string.Format(@"{0}\Repositories", projectPath);
14         irep.Output.Encoding = Encoding.UTF8;
15         irep.RenderToFile(Path.Combine(path, irep.FileName));
16     }
複製代碼

 

  生成的登陸記錄信息倉儲操做接口 ILoginLogRepository.generated.cs:

複製代碼
 1 //------------------------------------------------------------------------------
 2 // <auto-generated>
 3 //     此代碼由工具生成。
 4 //     對此文件的更改可能會致使不正確的行爲,而且若是
 5 //     從新生成代碼,這些更改將會丟失。
 6 //       如存在本生成代碼外的新需求,請在相同命名空間下建立同名分部類進行實現。
 7 // </auto-generated>
 8 //
 9 // <copyright file="ILoginLogRepository.generated.cs">
10 //        Copyright(c)2013 GMFCN.All rights reserved.
11 //        CLR版本:4.0.30319.239
12 //        開發組織:郭明鋒@中國
13 //        公司網站:http://www.gmfcn.net
14 //        所屬工程:GMF.Demo.Core.Data
15 //        生成時間:2013-06-16 17:56
16 // </copyright>
17 //------------------------------------------------------------------------------
18 
19 using System;
20 
21 using GMF.Component.Data;
22 using GMF.Demo.Core.Models;
23 
24 
25 namespace GMF.Demo.Core.Data.Repositories
26 {
27     /// <summary>
28     ///   數據訪問層接口——登陸記錄信息
29     /// </summary>
30     public partial interface ILoginLogRepository : IRepository<LoginLog>
31     { }
32 }
複製代碼

  若是 IRepository<T> 中定義的倉儲操做不知足登陸記錄倉儲操做的需求,只須要添加一個相應的分部接口,在其中進行需求的定義便可。這裏當前沒有額外的需求,就不須要額外定義了。

  3. 生成實體倉儲實現

  實體倉儲操做的實現與倉儲操做接口相似,這裏略過。

  完成生成後,代碼結構以下所示:

  若是添加了或者刪除了一個實體,只須要從新運行一下調用模板 EntityCodeScript.tt 便可從新生成新的代碼。

5、源碼獲取

  爲了讓你們能第一時間獲取到本架構的最新代碼,也爲了方便我對代碼的管理,本系列的源碼已加入微軟的開源項目網站 http://www.codeplex.com,地址爲:

  https://gmframework.codeplex.com/

  能夠經過下列途徑獲取到最新代碼:

  • 若是你是本項目的參與者,能夠經過VS自帶的團隊TFS直接鏈接到 https://tfs.codeplex.com:443/tfs/TFS17 獲取最新代碼
  • 若是你安裝有SVN客戶端(親測TortoiseSVN 1.6.7可用),能夠鏈接到 https://gmframework.svn.codeplex.com/svn 獲取最新代碼
  • 若是以上條件都不知足,你能夠進入頁面 https://gmframework.codeplex.com/SourceControl/latest 查看最新代碼,也能夠點擊頁面上的 Download 連接進行壓縮包的下載,你還能夠點擊頁面上的 History 連接獲取到歷史版本的源代碼
  • 若是你想和你們一塊兒學習MVC,學習EF,歡迎加入Q羣:5008599(羣發言僅限技術討論,拒絕閒聊,拒絕醬油,拒絕廣告)
  • 若是你想與我共同來完成這個開源項目,能夠隨時聯繫我。

系列導航

  1. MVC實用架構設計(〇)——整體設計
  2. MVC實用架構設計(一)——項目結構搭建
  3. MVC實用架構設計(二)——使用MEF應用IOC
  4. MVC實用架構設計(三)——EF-Code First(1):Repository,UnitOfWork,DbContext
  5. MVC實用架構設計(三)——EF-Code First(2):實體映射、數據遷移,重構
  6. MVC實用架構設計(三)——EF-Code First(3):使用T4模板生成類似代碼
  7. MVC實用架構設計(三)——EF-Code First(4):數據查詢
  8. MVC實用架構設計(三)——EF-Code First(5):二級緩存
  9. MVC實體架構設計(三)——EF-Code First(6):數據更新
  10. 未完待續。。。
若是您看完本篇文章感受不錯,請點擊一下右下角的 推薦來支持一下博主,謝謝!

做者:郭明鋒 出處http://www.cnblogs.com/guomingfeng

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索