当前位置 : 主页 > 编程语言 > c++ >

[VS2010] ADO.NET Entity Framework 新功能:永续保存无知对象 (Persistence-Ignorant Object)

来源:互联网 收集:自由互联 发布时间:2021-06-23
ADO.NET Entity Framework 的新功能:永续保存无知对象。可以说是 Entity Framework 划时代的新功能,颠覆一般的数据组件/DAL 与数据库间的交互方式。 前一篇文章介绍了 ADO.NET Entity Framework 的模

ADO.NET Entity Framework 的新功能:永续保存无知对象。可以说是 Entity Framework 划时代的新功能,颠覆一般的数据组件/DAL 与数据库间的交互方式。


前一篇文章介绍了 ADO.NET Entity Framework 的模型优先设计 (Model First Design) 功能,有没有觉得 .NET Framework 4.0 中的 ADO.NET Entity Framework 进步了很多呢?如果你这样就满足了,那接下来的东西你看了可能会像某啤酒广告的女主角们那样的尖叫~




一般在设计数据类的时候,大多都是以一个纯类 (轻量级类,只声明必要的属性代表字段,并没有和其他对象交互),包含几个只针对数据做处理的属性或方法等等,若要使用它和数据库连结时,只能在里面做一些 Property Mapping,并且另外撰写数据存取的 ADO.NET 程序,这个动作只要是当过应用程序开发人员,就会觉得如呼吸般自然 … 长久以来都是如此,没有一次例外。但 ADO.NET Entity Framework 2.0 试图将这个局面颠覆过来,开发人员可以直接使用纯类对象来生成数据结构,并且由 Entity Framework 代为建立数据库以及表格,这个方式可是以前 Visual Studio 开发人员前所未见的。这个方法在 Java 阵营中已经有一些实践品,而在 Java 阵营中对轻量级的数据对象一个特别的名词:POJO (Plain-old Java Object),在 .NET 阵营也有一个相对的名词,叫 POCO (Plain-old CLR Object),用途和 POJO 差不多,但微软给了一个笔者觉得很难翻的名词: Persistence-Ignorant Object,若直接翻译会变成 “保存无知型对象”,蛮拗口的,在官方翻译未出来前,就暂时先翻成 “无差别保存对象” (编按:在 "软件构筑美学" 一书中,将此词翻译为 "永续保存无知",笔者认为这个词翻的还不错,所以引用)?好了,因为 Persistence-Ignorant Object 具有不必事先在 DBMS 中建立实例数据库,就可以利用 Entity Framework 的 DDL Generation 功能将 POCO 对象结构转换成实例数据结构以存入数据库中的能力。

笔者认为永续保存无知对象在 ADO.NET Entity Framework 乃至于 ADO.NET 甚至是整个 .NET Framework 的 Data Access 机制而言,都是一项划时代的创新,它将数据存取组件设计的刻板印象完全的改变了,没想到只使用几个属性的声明就可以生成一个完成的数据结构,这可是许多开发人员梦寐以求的功能啊,笔者一开始看到这个功能时也是眼睛一亮,试过以后更觉得它是超级好物啊~

也许这样看起来还是有点抽象,实际走一次例子就知道了。不过在做例子前,请先看看环境是否符合:

A. 已安装 Visual Studio 2010

B. 下载并安装 ADO.NET Entity Framework Feature CTP2 : http://www.microsoft.com/downloads/details.aspx?FamilyID=13FDFCE4-7F92-438F-8058-B5B4041D0F01&displayLang=en

C. 已安装 SQL Server (最好是非 Express 版本,但 Express 版也无妨)

前置作业符合后,请依下列步骤执行:

1. 在 Visual Studio 中先建立一个 AdoEF_PocoExampleLibrary 类库项目,并且加入下列类声明程序 (可同在一个类库文件或是分成个别的文件):

public class Blog {
?? public Blog() { }
?? public int ID { get; set; }
?? public string Name { get; set; }
?? public string Url { get; set; }
?? public User Owner { get; set; }
?? public ICollection Posts { get; set; }
}

public class Comment
{
?? public Comment() { }
?? public int ID { get; set; }
?? public string Title { get; set; }
?? public string Body { get; set; }
?? public Person Author { get; set; }
?? public Post Post { get; set; }
?? public DateTime Created { get; set; }
?? public DateTime? Posted { get; set; }????
}

public class Person
{
?? public int ID { get; set; }
?? public string Firstname { get; set; }
?? public string Surname { get; set; }
?? public string EmailAddress { get; set; }
?? public ICollection Comments { get; set; }
}

public class Post
{
?? public Post() { }
?? public int ID { get; set; }
?? public string Title { get; set; }
?? public string Body { get; set; }
?? public string PermaUrl { get; set; }
?? public DateTime Created { get; set; }
?? public DateTime? Posted { get; set; }
?? public User Author { get; set; }
?? public User Poster { get; set; }
?? public Blog Blog { get; set; }
?? public ICollection Comments { get; set; }
?? public int BlogID { get; set; }
}

public class User : Person
{
?? public string Password { get; set; }
?? public ICollection Blogs { get; set; }
?? public ICollection AuthoredPosts { get; set; }
?? public ICollection PostedPosts { get; set; }
}

2. 在 Visual Studio 中建立一个 AdoEF_PocoExampleClient 主控台项目,先新增一个 BloggingModel 类,并将下列程序加入:

using System.Data.Entity;
using System.Data.EntityClient;
using System.Data.EntityModel;
using System.Data.Objects;

public class BloggingModel : ObjectContext
{
?? public BloggingModel(EntityConnection connection)
?????? : base(connection)
?? {
?????? DefaultContainerName = "BloggingModel";
?? }

??? public IObjectSet Blogs
?? {
?????? get { return base.CreateObjectSet (); }
?? }

??? public IObjectSet People
?? {
?????? get { return base.CreateObjectSet (); }
?? }

??? public IObjectSet Comments
?? {
?????? get { return base.CreateObjectSet (); }
?? }

??? public IObjectSet Posts
?? {
?????? get { return base.CreateObjectSet (); }
?? }
}

3. 在 AdoEF_PocoExampleClient 项目中加入一个 BlogDemo 类,并将下列程序加入(其中红字为数据库连线字符串,但 initial catalog 可以指定成目前还没建的数据库名称,若你已经有 Blogs 数据库,请将 initial catalog 的名称改一下,否则执行以后,你原有的 Blogs 数据库会被删掉):

using System.Data.Entity;
using System.Data.EntityClient;
using System.Data.EntityModel;
using System.Data.Objects;
using Microsoft.Data.Objects;

class BlogDemo
{
?? public static void Run()
?? {
?????? var builder = new ContextBuilder ();
?????? RegisterConfigurations(builder);
?????? var connection = new SqlConnection( "initial catalog=Blogs; integrated security=SSPI");

??????? using (var ctx = builder.Create(connection))
?????? {
?????????? if (ctx.DatabaseExists())
?????????????? ctx.DeleteDatabase();
?????????? ctx.CreateDatabase();
?????????? var EfDesign =
?????????????? new AdoEF_PocoExampleLibrary.Blog
?????????????? {
?????????????????? Name = "EF Design",
?????????????????? Url = "http://blogs.msdn.com/efdesign/",
?????????????????? Owner = new AdoEF_PocoExampleLibrary.User
?????????????????? {
?????????????????????? ID = 1,
?????????????????????? Firstname = "Johnny",
?????????????????????? Surname = "Miller",
?????????????????????? EmailAddress = "[email protected]",
?????????????????????? Password = "Viking"
?????????????????? }
?????????????? };

??????????? ctx.Blogs.AddObject(EfDesign);
?????????? var post = new AdoEF_PocoExampleLibrary.Post
?????????? {
?????????????? Title = "Hello",
?????????????? Blog = EfDesign,
?????????????? PermaUrl = EfDesign.Url + "/2009/08/Hello",
?????????????? Body = "....",
?????????????? Author = EfDesign.Owner,
?????????????? Poster = EfDesign.Owner,
?????????????? Created = DateTime.Today,
?????????????? Posted = DateTime.Today,
?????????? };

??????????? ctx.Posts.AddObject(post);
?????????? var comment = new AdoEF_PocoExampleLibrary.Comment
?????????? {
?????????????? Title = "RE:" + post.Title,
?????????????? Body = "Welcome to the world of blogging Johnny...",
?????????????? Created = DateTime.Now,
?????????????? Posted = DateTime.Now,
?????????????? Post = post,
?????????????? Author = new AdoEF_PocoExampleLibrary.Person
?????????????? {
?????????????????? ID = 2,
?????????????????? Firstname = "Vincent",
?????????????????? Surname = "Chase",
?????????????????? EmailAddress = "[email protected]",
?????????????? }
?????????? };

??????????? ctx.Comments.AddObject(comment);
?????????? ctx.SaveChanges();

??????????? AdoEF_PocoExampleLibrary.Blog blog = ctx.Blogs.Single();

??????????? foreach (var entry in blog.Posts)
?????????? {
?????????????? Console.WriteLine(entry.Title);
?????????????? Console.WriteLine(entry.Author.Firstname);
?????????? }
?????? }
?? }

??? static void RegisterConfigurations(ContextBuilder builder)
?? {
?????? builder.Configurations.Add(new CommentConfiguration());
?????? builder.Configurations.Add(new BlogConfiguration());
?????? builder.Configurations.Add(new PostConfiguration());
?????? builder.Configurations.Add(new PersonConfiguration());
?????? builder.Configurations.Add(new UserConfiguration());
?? }
}

4. 在前一步的程序的下方,加入下列的程序:

public class CommentConfiguration : EntityConfiguration
{
?? public CommentConfiguration()
?? {
?????? Property(c => c.ID).IsIdentity();
?????? Property(c => c.Title).HasMaxLength(103).IsRequired();
?????? Property(c => c.Body).IsRequired();
?????? // 1 to * relationships???????????
?????? Relationship(c => c.Author).IsRequired();
?????? Relationship(c => c.Post).IsRequired();
?????? //Register some inverses???????????
?????? Relationship(c => c.Post).FromProperty(p => p.Comments);
?????? Relationship(c => c.Author).FromProperty(u => u.Comments);
?? }
}

public class BlogConfiguration : EntityConfiguration
{
?? public BlogConfiguration()
?? {
?????? Property(b => b.ID).IsIdentity();
?????? Property(b => b.Name).HasMaxLength(100).IsRequired();
?????? Relationship(b => b.Owner).IsRequired();
?????? //Register some inverses???????????
?????? Relationship(b => b.Owner).FromProperty(u => u.Blogs);
?????? Relationship(b => b.Posts).FromProperty(p => p.Blog);
?? }
}

public class PostConfiguration : EntityConfiguration
{
?? public PostConfiguration()
?? {
?????? // Make the PK store generated???????????
?????? Property(p => p.ID).IsIdentity();
?????? // Convert some ‘0..1 to *‘ relationships into ‘1 to *‘???????????
?????? Relationship(p => p.Author).IsRequired();
?????? Relationship(p => p.Blog).IsRequired();
?????? Relationship(p => p.Poster).IsRequired();
?????? // Setup some facets???????????
?????? Property(p => p.Body).IsRequired();
?????? Property(p => p.PermaUrl).HasMaxLength(200);
?????? Property(p => p.Title).HasMaxLength(100);
?????? // Register some Inverses???????????
?????? Relationship(p => p.Author).FromProperty(u => u.AuthoredPosts);
?????? Relationship(p => p.Comments).FromProperty(c => c.Post);
?????? Relationship(p => p.Poster).FromProperty(p => p.PostedPosts);
?????? //BlogID is a FK property and Blog is a navigation property backed by this FK????
?????? Relationship(p => p.Blog).FromProperty(b => b.Posts).HasConstraint((p, b) => p.BlogID == b.ID);
?? }
}

public class PersonConfiguration : EntityConfiguration
{
?? public PersonConfiguration()
?? {
?????? Property(p => p.ID).IsIdentity();
?????? Property(p => p.Firstname).HasMaxLength(100);
?????? Property(p => p.Surname).HasMaxLength(100);
?????? Property(p => p.EmailAddress).HasMaxLength(200);
?????? MapHierarchy(
?????????? p => new
?????????? {
?????????????? pid = p.ID,
?????????????? email = p.EmailAddress,
?????????????? fn = p.Firstname,
?????????????? ln = p.Surname,
?????????? }
?????? ).ToTable("People");
?? }
}

public class UserConfiguration : EntityConfiguration
{
?? public UserConfiguration()
?? {
?????? Property(u => u.Password).HasMaxLength(15).IsRequired();
?????? Relationship(u => u.AuthoredPosts).FromProperty(p => p.Author);
?????? Relationship(u => u.PostedPosts).FromProperty(p => p.Poster);
?????? MapHierarchy(
?????????? u => EntityMap.Row(
?????????????? EntityMap.Column(u.ID, " u i d"),
?????????????? EntityMap.Column(u.Password)
?????????????? )
?????? ).ToTable("Users");
?? }
}

5. 在 AdoEF_PocoExampleClient 的 Program.cs 中,加入下列的程序:

class Program
{
?? static void Main(string[] args)
?? {
?????? BlogDemo.Run();
?? }
}

6. 若你所使用的数据库是 SQL Server (非 Express 或 Compact Edition),可将 SQL Profiler 先启动并进入监听模式。

7. 按 F5 以调试器执行或按 CTRL+F5 直接执行,正常情况下窗口会出现以后消失。此时请打开 SQL Server Management Studio 并连到本机服务器中,即可以看到新的 Blogs 数据库。

8. 若在前面有启动 SQL Profiler 监听,则可以将它停止后,看看 Entity Framework 做了什么事:

如何,是不是有想要尖叫的感觉呢?有了这样的机制,Entity Framework 更向成熟的 ORM Framework 迈进一大步了。

由于这个功能太大,一回文章介绍不完,因此笔者下回再继续深入介绍这个神奇的功能。

参考数据:

Updated Feature CTP Walkthrough: Code Only for Entity Framework

http://blogs.msdn.com/adonet/archive/2009/11/12/updated-feature-ctp-walkthrough-code-only-for-entity-framework.aspx

范例程序下载:

http://blogs.msdn.com/adonet/attachment/9921786.ashx

原文:大专栏  [VS2010] ADO.NET Entity Framework 新功能:永续保存无知对象 (Persistence-Ignorant Object) Overview

网友评论