使用Entity Framework 6 Code First與新資料庫建立應用程式

by vivid 13. 八月 2014 03:02

.NET Magazine國際中文電子雜誌
者:許薰尹
稿:張智凱
文章編號:N140815101
出刊日期:2014/8/13
開發工具:Visual Studio 2013 Ultimate Update 2
版本:.NET Framework 4.5.x + ASP.NET MVC 5.x

在Entity Framework 6版本中,使用Entity Framework設計資料庫存取程式的方式分為三種:

  • Database First:先有資料庫的結構描述資訊,利用設計工具,做逆向工程,產生模型(Model),並產生對應的Entity 類別。
  • Model First:先使用設計工具建立模型(Model),再利用模型來建立資料庫結構描述資訊,並產生對應的Entity 類別。
  • Code First:先定義Entity類別與對應(mapping)的程式碼,再根據搭配的資料庫分為兩種設計方式:
    • 使用新資料庫:由模型自動產生資料庫結構描述資訊。搭配Code First Migration處理後續資料庫結構描述異動的問題。
    • 使用既存資料庫:從現有資料庫結構描述資訊,搭配逆向工程工具還原模型(Model),產生對應的Entity 類別。

本文將介紹使用Entity Framework 6 Code First與新資料庫建立ASP.NET MVC 5應用程式,並說明在後續模型異動的情況下,要如何自動地變更資料庫結構描述資訊。

我們從建立一個ASP.NET MVC 5應用程式開始。啟動Visual Studio 2013開發環境。從「File」-「New」-「Project」,在「New Project」對話盒中,設定上方的清單的.NET Framework版本為「.NET Framework 4.5.1」;選取左方「Installed」清單-「Templates」-「Visual C#」程式語言,從「Web」分類中,選取「ASP.NET Web Application」。設定專案名稱為「CFNewDB」。設定專案存放路徑,然後按下「OK」鍵,請參考下圖所示:

clip_image002

圖 1:建立一個ASP.NET MVC 5應用程式。

在「New ASP.NET Project」對話盒中選取「Empty」,勾選下方的「MVC」,然後按下「OK」按鈕建立專案,請參考下圖所示:

clip_image004

圖 2:建立空白MVC專案。

安裝Entity Framework套件

ASP.NET MVC 5空白網站預設沒有安裝Entity Framework套件。我們可以從Visual Studio 2013開發工具-「Solution Explorer」- 專案 - 「Manage NuGet Packages」開啟「Manage NuGet Packages」對話盒,選取左方「Online」清單項目, 在右上方文字方塊中輸入「Entity Framework」關鍵字,搜尋「Entity Framework」,按下「Install」按鈕做安裝。(注意,Entity Framework的版本要6.1以上版本),請參考下圖所示:

clip_image006

圖 3:安裝Entity Framework套件。

若使用Nuget套件管理員下載「Entity Framework」函式庫時,無法找到想使用的Entity Framework版本,你可以直接在Visual Studio工具中下指令下載,並指明想使用的版本。步驟為:在「Solution Explorer」視窗選取專案名稱。從Visual Studio 2013開發工具「TOOLS」-「Library Package Manager」-「Package Manage Console」開啟「Package Manage Console」視窗,然後在提示字元中輸入install-package指令,並使用「-version」指定安裝Entity Framework 6.1.1版本:

Install-Package EntityFramework -Version 6.1.1
 

新增ADO.NET實體資料模型

下一步是定義ADO.NET實體資料模型(ADO.NET Entity Data Model),在MVC的專案之中,通常將ADO.NET實體資料模型的相關程式置於Models資料夾之中。從Visual Studio 2013開發工具-「Solution Explorer」- 專案-「Models」目錄上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」,開啟「Add New Item」對話盒,從右上方文字方塊輸入「ado.net」搜尋,選取「ADO.NET Entity Data Model」,設定名稱為「OperaContext」,然後按下「Add」按鈕,建立新模型,請參考下圖所示:

clip_image008

圖 4:新增OperaContext模型。

接下來在「Entity Data Model Wizard」視窗之中,可以看到目前包含四個選項:

  • EF Designer from Database:應用在Database First設計。
  • Empty EF Designer model:應用在Model First設計。
  • Empty Code First model :應用在Code First設計,新增模型項目。
  • Code First from database :應用在Code First設計,以現有資料庫新增模型項目。

由於我們的目的是新增一個新的資料庫來儲存資料,在此步驟則選取「Empty Code First model」項目,然後按下「Finish」按鈕,請參考下圖所示:

clip_image010

圖 5:選取「Empty Code First model」項目。

Visual Studio將會自動在Models資料夾之中產生一個OperaContext.cs檔案,其中包含OperaContext類別,定義如下,OperaContext類別將繼承DbContext類別,負責連結到實體資料庫,類別的建構函式之中,則叫用父類別的建構函式,指明要使用的連接字串名稱為「OperaContext」:

namespace CFNewDB.Models {
  using System;
  using System.Data.Entity;
  using System.Linq;

  public class OperaContext : DbContext {
    // Your context has been configured to use a 'OperaContext' connection string from your application's
    // configuration file (App.config or Web.config). By default, this connection string targets the
    // 'CFNewDB.Models.OperaContext' database on your LocalDb instance.
    //
    // If you wish to target a different database and/or database provider, modify the 'OperaContext'
    // connection string in the application configuration file.
    public OperaContext( )
      : base( "name=OperaContext" ) {
    }

    // Add a DbSet for each entity type that you want to include in your model. For more information
    // on configuring and using a Code First model, see http://go.microsoft.com/fwlink/?LinkId=390109.

    // public virtual DbSet<MyEntity> MyEntities { get; set; }
  }

  //public class MyEntity
  //{
  //    public int Id { get; set; }
  //    public string Name { get; set; }
  //}
}


此外,也會在網站的Web.config檔案之中,加上連接到資料庫的查詢字串,定義如下,預設使用(localdb)來儲存資料:

<connectionStrings>

<add name="OperaContext" connectionString="data source=(LocalDb)\v11.0;initial catalog=CFNewDB.Models.OperaContext;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />

</connectionStrings>

新增Opera模型

下一步是定義模型,在此新增一個Opera類別。從Visual Studio 2013開發工具-「Solution Explorer」視窗- 專案 -「Models」目錄上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」,開啟「Add New Item」對話盒,從右上方文字方塊輸入「Class」搜尋,選取Class,設定名稱為「Opera」,然後按下「Add」按鈕,建立新類別,請參考下圖所示:

clip_image012

圖 6:新增Opera模型。

在Opera.cs檔案定義以下Opera類別,包含OperaID、Title 、Year與Composer四個屬性:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace CFNewDB.Models {
  public class Opera {
    public int OperaID { get; set; }
    public string Title { get; set; }
    public int Year { get; set; }
    public string Composer { get; set; }
  }
}


OperaContext類別繼承System.Data.Entity命名空間下的 DbContext類別。預設Entity Framework會將模型中名為id屬性(或類別名稱+ID)對應到資料表的主鍵欄位,例如此範例中Opera類別中代表編號的OperaID屬性將對應到資料表主鍵欄位,且利用DatabaseGeneratedOption.Identity設定為自動編號欄位。

 

使用OperaContext讀寫資料

選取Visual Studio 2013工具「Build」-「Build Solution」建置專案。完成模型的建置動作之後,便可以利用OperaContext來讀寫資料庫資料。

 

新增控制器

下一步我們來透過Visual Studio 2013的「Add Scaffold」功能來建立控制器,以及展現資料的檢視(View)。在「Solution Explorer」視窗,專案的「Controllers」資料夾上方,按滑鼠右鍵,選取「Add」-「Controller」,此時會開啟「Add Scaffold」視窗,選取「MVC 5 Controller with views, using Entity Framework」,然後按下「Add」按鈕,請參考下圖所示:

clip_image014

圖 7:使用「Add Scaffold」功能新增控制器。

在「Add Controller」視窗設定以下資料:

  • Model Class :「Opera (CFNewDB.Models)」。
  • Data context class:「OperaContext (CFNewDB.Models)」。
  • 勾選中間的「Generate views」,清除勾選其它核取方塊
  • Controller Name:「OperaController」。

完成的結果,請參考下圖所示:

clip_image016

圖 8:Add Controller。

Visual Studio 2013會自動在專案中「Views\Opera」資料夾下,產生Index.cshtml、Edit.cshtml、Details.cshtml、Delete.cshtml與Create.cshtml檔案,以及顯示資料的程式碼。以下則是Controller的程式碼:

namespace CFNewDB.Controllers
{
    public class OperaController : Controller
    {
        private OperaContext db = new OperaContext();

        // GET: Opera
        public ActionResult Index()
        {
            return View(db.Operas.ToList());
        }

        // GET: Opera/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Opera opera = db.Operas.Find(id);
            if (opera == null)
            {
                return HttpNotFound();
            }
            return View(opera);
        }

        // GET: Opera/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Opera/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "OperaID,Title,Year,Composer")] Opera opera)
        {
            if (ModelState.IsValid)
            {
                db.Operas.Add(opera);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            return View(opera);
        }

        // GET: Opera/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Opera opera = db.Operas.Find(id);
            if (opera == null)
            {
                return HttpNotFound();
            }
            return View(opera);
        }

        // POST: Opera/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "OperaID,Title,Year,Composer")] Opera opera)
        {
            if (ModelState.IsValid)
            {
                db.Entry(opera).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(opera);
        }

        // GET: Opera/Delete/5
        public ActionResult Delete(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Opera opera = db.Operas.Find(id);
            if (opera == null)
            {
                return HttpNotFound();
            }
            return View(opera);
        }

        // POST: Opera/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(int id)
        {
            Opera opera = db.Operas.Find(id);
            db.Operas.Remove(opera);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

 

以下則是自動產生在Views\Opera資料夾中Index.cshtml檔案的程式碼:

@model IEnumerable<CFNewDB.Models.Opera>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
    <p>
        @Html.ActionLink("Create New", "Create")
    </p>
    <table class="table">
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Year)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Composer)
            </th>
            <th></th>
        </tr>
   
    @foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Year)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Composer)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id=item.OperaID }) |
                @Html.ActionLink("Details", "Details", new { id=item.OperaID }) |
                @Html.ActionLink("Delete", "Delete", new { id=item.OperaID })
            </td>
        </tr>
    }
   
    </table>
</body>
</html>

 

最後測試一下首頁,從「Solution Explorer」視窗- 選取Views\Opera資料夾下的Index.cshtml檔案,按CTRL+F5執行Index 檢視,執行結果參考如下:

clip_image018

圖 9:Index檢視測試。

檢視資料庫結構描述資訊

完成以上的動作之後,資料庫已經建立了。根據連接字串的設定,資料庫會放在(localdb)資料庫之中,我們來利用Visual Studio 2013檢視新建立的資料庫以及其結構描述資訊。開啟Visual Studio 2013 「Server Explorer」視窗,你將可以看到「Data Connections」節點之下,出現一個OperaContext節點,展開此節點,完成後應如下圖所示:

clip_image020

圖 10:建立連線。

從「Server Explorer」視窗中,你就可以看到新增的Operas資料表。試著點選Index網頁中的「Create New」連結,請參考下圖所示:

clip_image022

圖 11:新增資料。

接著進入資料新增畫面,新增幾筆資料,請參考下圖所示:

clip_image024

圖 12:新增資料。

啟用資料移轉功能

當你的應用程式在繼續開發的過程中,資料庫的結構描述資訊可能會需要修改,此時你可以使用Entity Framework 的Code First Migration功能來因應異動的部分。Code First Migration可以記住你資料庫結構描述異動過程中的各個版本。

首先你需要在專案之中啟用資料移轉功能:從Visual Studio 2013開發工具「TOOLS」-「Library Package Manager」-「Package Manage Console」開啟「Package Manage Console」視窗,然後在提示字元中輸入enable-migrations,啟用Entity Framework資料庫移轉功能:

enable-migrations

此命令的執行結果,請參考下圖所示:

clip_image026

圖 13:啟用移轉。

接著Visual Studio 2013工具會自動在專案中產生一個「Migrations」資料夾,其中包含一個Configuration.cs檔案,其中有一個Seed方法,可以在其中加入初始化資料庫Operas資料表資料的程式碼:

namespace CFNewDB.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<CFNewDB.Models.OperaContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
            ContextKey = "CFNewDB.Models.OperaContext";
        }

        protected override void Seed(CFNewDB.Models.OperaContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
}

 

此外還有一個XXX_InitialCreate.cs檔案(XXX代表時間戳記),其中包含程式碼,描述目前從空的資料庫到現在包含一個Operas資料表的結構資訊:

namespace CFNewDB.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
   
    public partial class InitialCreate : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Operas",
                c => new
                    {
                        OperaID = c.Int(nullable: false, identity: true),
                        Title = c.String(),
                        Year = c.Int(nullable: false),
                        Composer = c.String(),
                    })
                .PrimaryKey(t => t.OperaID);
           
        }
       
        public override void Down()
        {
            DropTable("dbo.Operas");
        }
    }
}

 

修改模型

好了,現在讓我們修改原來的Opera模型,在Opera類別之中加入一個字串型別的Language屬性,記錄Opera的語言:

 

namespace CFNewDB.Models {
  public class Opera {
    public int OperaID { get; set; }
    public string Title { get; set; }
    public int Year { get; set; }
    public string Composer { get; set; }
    public string Language { get; set; }
  }
}

 

 

新增資料遷移

接著我們從Visual Studio 2013開發工具「TOOLS」-「Library Package Manager」-「Package Manage Console」開啟「Package Manage Console」視窗,然後在提示字元中輸入指令新增資料遷移記錄:

Add-Migration AddLanguageColumn

此命令的執行結果,請參考下圖所示:

clip_image028

圖 14:新增資料遷移。

Visual Studio將會在Migrations資料夾之下,加入一個XXXX_ AddLanguageColumn.cs檔案(XXX代表時間戳記),其中包含程式碼,描述目前從上一次模型異動的結果,到現在個Operas資料表多一個Language欄位的差異之結構資訊:

namespace CFNewDB.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
   
    public partial class AddLanguageColumn : DbMigration
    {
        public override void Up()
        {
            AddColumn("dbo.Operas", "Language", c => c.String());
        }
       
        public override void Down()
        {
            DropColumn("dbo.Operas", "Language");
        }
    }
}

 

選取Visual Studio 2013工具「Build」-「Build Solution」建置專案。從Visual Studio 2013開發工具「TOOLS」-「Library Package Manager」-「Package Manage Console」開啟「Package Manage Console」視窗,然後在提示字元中輸入update-database,指定Verbose參數:

update-database –Verbose

執行結果請參考下圖所示,你可以發現Visual Studio送出ALTER Table指令,更新後端資料庫Operas資料表的結構:

clip_image030

圖 15:新增資料欄位。

Operas資料表將新增一個Language欄位,請參考下圖所示:

clip_image032

圖 16:Operas資料表新增一個Language欄位。

此時若查詢資料庫中Operas資料表資料,你將發現,先前測試時所新增的資料還在資料庫之中,請參考下圖所示:

clip_image034

圖 17:查詢Operas資料表資料。

Tags:

.NET Magazine國際中文電子雜誌 | ASP.NET MVC | Entity Framework | 許薰尹Vivid Hsu

評論 (49) -

manhoef
manhoef Taiwan
2015/8/31 下午 01:53:25 #

你好
我想請問一下,在 "接下來在「Entity Data Model Wizard」視窗之中,可以看到目前包含四個選項" 這個步驟
為什麼我只有兩個項目可以選擇
從資料庫產生、空的模型
我是安裝visual studio 2013版本  有裝entity framework 5
謝謝

回覆

Vivid
Vivid Taiwan
2015/9/4 下午 01:07:41 #

你需要安裝Visual Studio 2013 Update,目前最新版是Visual Studio 2013 Update 5

回覆

Vivid
Vivid Taiwan
2015/9/4 下午 01:24:31 #

對了還要安裝Entity Framework 6 Tools for Visual Studio 2012 & 2013 (www.microsoft.com/.../details.aspx?id=40762)

回覆

cours de theatre paris
cours de theatre paris United States
2017/10/1 上午 01:21:30 #

Great post.Really thank you! Want more.

回覆

dic phoenix
dic phoenix United States
2017/10/7 上午 02:10:29 #

I really enjoy the article post.Really thank you! Will read on...

回覆

Osimi seaview
Osimi seaview United States
2017/10/9 下午 07:58:26 #

Major thanks for the article.Much thanks again. Will read on...

回覆

buy hacklink google
buy hacklink google United States
2017/10/12 下午 10:36:45 #

I really like and appreciate your article post. Cool.

回覆

that site
that site United States
2017/10/14 下午 05:53:35 #

I loved your blog article.Really thank you! Really Cool.

回覆

dragon city hack apk
dragon city hack apk United States
2017/10/15 下午 05:24:02 #

I really enjoy the article.Much thanks again. Really Great.

回覆

try here
try here United States
2017/10/17 下午 04:42:51 #

Thanks a lot for the post.Much thanks again. Really Cool.

回覆

sletrokor review
sletrokor review United States
2017/10/17 下午 10:14:24 #

A round of applause for your post.Really looking forward to read more. Keep writing.

回覆

VigRx
VigRx United States
2017/10/19 上午 09:18:13 #

Muchos Gracias for your blog article.Really looking forward to read more. Fantastic.

回覆

Look At This
Look At This United States
2017/10/19 下午 08:26:07 #

Wow, great blog.

回覆

carte grise en ligne
carte grise en ligne United States
2017/10/21 上午 09:25:45 #

I really liked your article post.Much thanks again. Really Great.

回覆

phentaslim review
phentaslim review United States
2017/11/3 下午 02:51:05 #

Very good blog article.Thanks Again. Much obliged.

回覆

spinal stenosis treatment alternative
spinal stenosis treatment alternative United States
2017/11/15 上午 04:42:53 #

I appreciate you sharing this blog post.Really looking forward to read more. Great.

回覆

avocat criminel quebec
avocat criminel quebec United States
2017/11/16 下午 03:21:52 #

Wow, great blog post.Really looking forward to read more. Want more.

回覆

Major thanks for the blog article.Much thanks again. Cool.

回覆

fiverr tips
fiverr tips United States
2017/11/21 下午 11:46:46 #

Thanks for the blog post.Much thanks again. Fantastic.

回覆

fashion
fashion United States
2017/11/23 下午 06:41:56 #

I value the article post.Really thank you! Cool.

回覆

Social Media Management Auckland
Social Media Management Auckland United States
2017/11/25 下午 03:42:37 #

Thanks for the blog.Really looking forward to read more. Cool.

回覆

Chad Boonswang and Jeffrey Goodman
Chad Boonswang and Jeffrey Goodman United States
2017/11/26 下午 02:54:19 #

Looking forward to reading more. Great article post.Much thanks again. Keep writing.

回覆

Chad Boonswang SEO
Chad Boonswang SEO United States
2017/11/26 下午 08:50:26 #

Thanks so much for the article.Really thank you! Great.

回覆

car wreckers
car wreckers United States
2017/11/29 下午 01:15:50 #

Im obliged for the blog.Thanks Again. Will read on...

回覆

primary trade lines
primary trade lines United States
2017/11/30 下午 09:41:59 #

Hey, thanks for the post.Much thanks again. Want more.

回覆

porno
porno United States
2017/12/1 下午 01:25:05 #

Thank you for your blog article.Much thanks again. Will read on...

回覆

commercial real estate loan
commercial real estate loan United States
2017/12/3 上午 01:39:18 #

Very informative blog post.Thanks Again. Want more.

回覆

free porn app
free porn app United States
2017/12/5 上午 06:28:55 #

Awesome post. Fantastic.

回覆

A round of applause for your article post.Really thank you! Want more.

回覆

I really liked your article.Thanks Again. Keep writing.

回覆

michel lawyer
michel lawyer United States
2017/12/10 下午 03:17:11 #

Really enjoyed this article.Much thanks again. Much obliged.

回覆

Elwood Calicut
Elwood Calicut United States
2017/12/14 上午 06:17:44 #

I really liked your article post. Will read on...

回覆

go to this website
go to this website United States
2017/12/14 下午 01:07:51 #

Thanks for the article.Much thanks again. Much obliged.

回覆

Hanukkah
Hanukkah United States
2017/12/14 下午 07:34:23 #

A big thank you for your blog post.Thanks Again. Want more.

回覆

canon driver software
canon driver software United States
2017/12/16 下午 02:50:23 #

I truly appreciate this blog article.Really thank you! Will read on...

回覆

green coffee bean
green coffee bean United States
2017/12/16 下午 09:01:18 #

Fantastic article post.Much thanks again. Will read on...

回覆

degreeshortcut
degreeshortcut United States
2017/12/17 下午 09:34:04 #

Really appreciate you sharing this article post.

回覆

financial freedom
financial freedom United States
2017/12/20 下午 03:40:31 #

Thank you ever so for you blog article.Thanks Again. Much obliged.

回覆

canon drivers
canon drivers United States
2017/12/23 下午 01:29:09 #

I really like and appreciate your article.Thanks Again. Will read on...

回覆

Thanks for sharing, this is a fantastic article.Thanks Again. Great.

回覆

SOCCER HIGHLIGHTS
SOCCER HIGHLIGHTS United States
2017/12/26 下午 05:38:31 #

Great, thanks for sharing this article post. Great.

回覆

hp drivers
hp drivers United States
2018/1/2 下午 01:04:48 #

Major thanks for the blog article.Really thank you! Really Great.

回覆

hp drivers
hp drivers United States
2018/1/3 下午 12:25:39 #

Thank you ever so for you article post.Thanks Again. Fantastic.

回覆

online slots real money usa
online slots real money usa United States
2018/1/4 下午 11:18:34 #

I value the article.Thanks Again. Will read on...

回覆

hp printer driver
hp printer driver United States
2018/1/5 下午 03:45:01 #

Im thankful for the blog article.Really thank you! Will read on...

回覆

FBA
FBA United States
2018/1/6 上午 07:49:23 #

Thank you ever so for you post. Really Cool.

回覆

web hosting
web hosting United States
2018/1/10 下午 12:24:19 #

I think this is a real great blog. Much obliged.

回覆

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List