代码改变世界

【转】【翻译】Entity Framework 特性CTP全程示范: Code Only

2009-08-17 11:05  E2Home  阅读(875)  评论(0编辑  收藏  举报

【原文地址】Feature CTP Walkthrough: Code Only for the Entity Framework
【原文发表日期】 22 June 09 02:54 PM

【译注】.NET 3.5 SP1中的Entity Framework着重于“数据库优先(Database First)”,即从数据库中逆工程生成实体数据模型。而Visual Studio 2010/.NET 4.0中的Entity Framework 4.0引进了“模型优先(Model First)”,即允许你先生成实体数据模型,然后生成映射到该模型的数据库。而Entity Framework Feature CTP1版则更进一步,推出了“只用代码(Code Only)”的预览版,不再需要EDMX文件。 相关的想法请参考这个贴子。你需要下列软件才能运行这个示范:
  1. Visual Studio 2010 Beta 1
  2. Entity Framework Feature CTP1 (同时参考Entity Framework Feature CTP 1一文,如果你对该CTP中其他特性,特别是POCO模板等,感兴趣的话)
  3. 本地的SQL Server 2008 Express或者SQL Server

Code Only全程示范

1) 创建一个名叫“"CodeOnlyWalkthru"”的控制台应用:

blog1

2) 往"CodeOnlyWalkThru"解决方案中加一个新的项目:

blog1

3) 选择“类库”,将其命名为"Entities":

blog1

 

4) 在你的Entities项目中加一个"Category"类:

右击Entities项目,加一个名叫“"Category"”的类,然后将下面的代码粘贴入该类:

public class Category
{
private List<Product> _products;
public int ID { get; set; }
public string Name { get; set; }
public virtual List<Product> Products {
get
{
if (_products == null)
_products = new List<Product>();
return _products;
}
set
{
_products = value;
}
}
}

 

5) 生成"Product"类:

在"Category.cs"类中,右击还不存在的Product类名,从上下文菜单上选择"Generate > Class(生成类)":

blog1

在新的Product类中,粘贴入下面这些代码:

public class Product
{
public int ID { get; set; }
public string Name { get; set; }
}

至此,你的项目应该象这样:

blog1

我们把这些实体类放进了一个单独的项目,这样它们会被编译进一个对Entity Framework无依赖的程序集中。因此,Entities程序集对持久性是透明的,这对一些开发人员来说,是非常重要的。对持久性有意识的代码存在于另外的程序集中,引用对持久性是透明的程序集。

6) 在"CodeOnlyWalkThru"项目中,添加对Entities项目的引用:

blog1

7) 在"CodeOnlyWalkThru"项目中,添加对"System.Data.Entity" 和 "Microsoft.Data.Entity.Ctp"的引用:

blog1

image

注: 从长远看来,我们计划将“Code Only”的功能并入核心的Entity Framework程序集。之后,你就只需第一个引用。

8) 在"CodeOnlyWalkThru" 项目中,加一个新的叫"ProductDBContext"的类:

 

blog1

9) 将下面的代码加到"ProductDBContext"类中:

public class ProductDBContext: ObjectContext
{
public ProductDBContext(EntityConnection connection)
: base(connection, "ProductDBContext")
{
ContextOptions.DeferredLoadingEnabled = true;
}
public IObjectSet<Category> Categories
{
get { return CreateObjectSet<Category>(); }
}
public IObjectSet<Product> Products
{
get { return CreateObjectSet<Product>(); }
}
}

因为这个类扩充了ObjectContext,它代表你的模型的形状,起通往你的数据库的入口的作用。注意,我们为上面两个实体类型创建了对应的ObjectSet集。 我们还加了一个构造器,它接受一个EntityConnection参数。ContextBuilder会制造一个EntityConnection (EntityConnection封装了实际的数据库连接和Entity Framework元数据(metadata)),在我们要求它生成一个ProductDBContext新实例时,会将该参数传给这个构造器。在构造器中,我们还配置Entity Framework启用DeferredLoading(即LazyLoading-懒式装载)。

10) 然后将下面的代码粘贴进"Program" 类:

SqlConnection connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;Initial Catalog=ProductDB;Integrated Security=SSPI;");
using (ProductDBContext context = ContextBuilder.Create<ProductDBContext>(connection))
{
if (!context.DatabaseExists())
context.CreateDatabase();
Category food = new Category { CID = 1, Name = "Food" };
Product bovril = new Product { ID = 1, Name = "Bovril" };
Product marmite = new Product { ID = 2, Name = "Marmite" };
Product vegemite = new Product { ID = 3, Name = "Vegemite" };
food.Products.Add(bovril);
food.Products.Add(marmite);
food.Products.Add(vegemite);
context.Categories.AddObject(food);
context.SaveChanges();
// Query the database
food = context.Categories.Single();
foreach (var product in food.Products)
Console.WriteLine(product.Name);
}

 

上面的代码按约定创建了一个上下文,连向本地安装的SQLExpress中的ProductDB数据库。如果ProductDB数据库还不存在,就创建该数据库。

最后,在上下文开始运行后,你就象平常一样使用它,在这个例子中,我们创建了一个Category实例,三个Product实例,两者互相关联,然后我们从数据库中获取Category对象,然后使用LazyLoading(即DeferredLoading),对它的产品进行循环。

就是这么简单!

11) 配置ContextBuilder

迄今为止,我们是按约定来做一切的,因为Code Only可以按约定推断出任何东西。但如果我们将Category类改成象这样的话:

public class Category
{
private List<Product> _products;
public int CID { get; set; }
public string Name { get; set; }
public virtual List<Product> Products {
get
{
if (_products == null)
_products = new List<Product>();
return _products;
}
set
{
_products = value;
}
}
}

CodeOnly不知道CID是键(key)【见注】,这意味着你需要创建一个ContextBuilder实例,用它来将CID注册成键,象这样:

var builder = new ContextBuilder<ProductDBContext>();
builder.RegisterKey((Category c) => c.CID);

如果需要的话,你可以在同个Builder上注册许多个键,你配置完你的Builder之后,你可以使用它的Create方法来创建一个ProductDBContext实例:

using (ProductDBContext context = builder.Create(connection))

 

其它的代码没变。

一般来说,在需要创建ObjectContext时,你应该重用你配置的ContextBuilder,而不是每次都重新配置,这会对性能有帮助。最好的做法大概是通过一个静态变量来做。

【注】按约定,任何叫ID, Id, ClassNameID 或 ClassNameId的属性会被假定为实体键。如果找不到这些名称的属性的话,那么你需要调用RegisterKey(),来告诉Entity Framework哪个属性是键。

Beta1版的CTP中Code Only功能的已知限制:

这个版本是一个非常早期的Code Only预览版,因此它有许多已知的限制,我们计划在以后的版本中解决它们,这些限制包括:

  • 不支持复杂类型(ComplexType)
  • 不支持可配置的映射
  • 只支持Table per Hierarchy继承策略
  • 不支持Facet的指定,譬如,你无法指定数据库中一个字符串字段的最大长度,而只用默认值
  • 没有提供器模型(Provider Model),所以CodeOnly 目前只支持SqlServer
  • CodeOnly没有提供方式让你指定哪个属性参与了同个关系,但只是对方的倒转(inverse)。譬如,如果在上面的例子中,你往Product类中加了一个Category属性, 结果在Product和Category间,会有2个关系,因此在Products表中会生成2个外键,因为Entity Framework无法推断Product.Category和Category.Products只是对方的倒转。
  • 不支持多对多关系

- Alex James
Entity Framework的Program Manager



推荐文章