转抄一个EF的例子
(Fluent)API建立实体模型,太好了! 这才是我想要的*!
原文:http://blog.joycode.com/saucer/
【翻译】EF 特性 CTP5版: 流畅 API 例子
【原文地址】EF Feature CTP5: Fluent API Samples
【原文发表日期】 6 Dec 2010 9:00 PM
我们刚发布了实体框架特性第五个社区技术预览版 (简称CTP5)。 特性CTP5版包括了我们计划在2011年第一个季度以独立的软件包形式发布的新特性的预览内容,希望得到大家的反馈。特性CTP5版建立在随.NET框架4.0和Visual Studio 2010发布的现有实体框架4(简称EF4)的功能之上,是我们先前CTP版本的更新版。
Code First提供了一个流畅(Fluent)API,可以用来进一步配置一个模型,本贴将提供一系列使用流畅API的简短例程。
注: 流畅 API是个比较高级的概念,本贴假定你对代码优先简介一文中详述的概念有所理解。
模型
在本贴展示的例程会使用下述模型:
public class ProductContext : DbContext { public DbSet<Category> Categories { get; set; } public DbSet<Product> Products { get; set; } public DbSet<Tag> Tags { get; set; } public DbSet<Person> People { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<OrderLine> OrderLines { get; set; } public DbSet<OrderLineNote> OrderLineNotes { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { // TODO: Use Fluent API Here } } public class Category { public string CategoryCode { get; set; } public string Name { get; set; } public virtual ICollection<Product> Products { get; set; } } public class Product { public int ProductId { get; set; } public string Name { get; set; } public string PrimaryCategoryCode { get; set; } public virtual Category PrimaryCategory { get; set; } public string SecondaryCategoryCode { get; set; } public virtual Category SecondaryCategory { get; set; } public virtual ICollection<Tag> Tags { get; set; } } public class DiscontinuedProduct : Product { public DateTime DiscontinuedDate { get; set; } } public class Tag { public string TagId { get; set; } public virtual ICollection<Product> Products{ get; set; } } public class Person { public int PersonId { get; set; } public string Name { get; set; } public Address Address { get; set; } public ICollection<Order> Orders { get; set; } } public class Address { public string Street { get; set; } public string City { get; set; } public string State { get; set; } public string Zip { get; set; } } public class Order { public int OrderId { get; set; } public DateTime OrderDate { get; set; } public ICollection<OrderLine> Lines { get; set; } public Person Person { get; set; } } public class OrderLine { public int OrderId { get; set; } public int ProductId { get; set; } public int Quantity { get; set; } public Product Product { get; set; } public ICollection<OrderLineNote> Notes { get; set; } } public class OrderLineNote { public int OrderId { get; set; } public int ProductId { get; set; } public string Note { get; set; } public OrderLine OrderLine { get; set; } }
主键
简单的主键:
modelBuilder.Entity<Category>()
.HasKey(c => c.CategoryCode);
复合主键:
modelBuilder.Entity<OrderLine>()
.HasKey(l => new { l.OrderId, l.ProductId });
属性
将一个在CLR中可为null的属性设成必需的:
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired();
改变字符串长度:
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.HasMaxLength(50);
关闭Identity:
modelBuilder.Entity<Product>()
.Property(p => p.ProductId)
.HasDatabaseGenerationOption(DatabaseGenerationOption.None);
忽略一个属性:
modelBuilder.Entity<Person>()
.Ignore(p => p.Name);
类型
指定一个类型为复杂类型:
modelBuilder.ComplexType<Address>();
忽略一个类型:
modelBuilder.Ignore<Person>();
关系
标准的一对多:
modelBuilder.Entity<Product>()
.HasRequired(p => p.PrimaryCategory)
.WithMany(c => c.Products)
.HasForeignKey(p => p.PrimaryCategoryCode);
同样的关系也可从另一端配置(其效果与上面的代码相同):
modelBuilder.Entity<Category>()
.HasMany(c => c.Products)
.WithRequired(p => p.PrimaryCategory)
.HasForeignKey(p => p.PrimaryCategoryCode);
只有一个导航属性的关系:
modelBuilder.Entity<OrderLine>()
.HasRequired(l => l.Product)
.WithMany()
.HasForeignKey(l => l.ProductId);
关闭级联删除:
modelBuilder.Entity<Category>()
.HasMany(c => c.Products)
.WithRequired(p => p.PrimaryCategory)
.HasForeignKey(p => p.PrimaryCategoryCode)
.WillCascadeOnDelete(false);
拥有复合外键的关系:
modelBuilder.Entity<OrderLineNote>()
.HasRequired(n => n.OrderLine)
.WithMany(l => l.Notes)
.HasForeignKey(n => new { n.OrderId, n.ProductId });
将没在对象模型中呈示的外键重新命名:
modelBuilder.Entity<Order>()
.HasRequired(o => o.Person)
.WithMany(p => p.Orders)
.IsIndependent()
.Map(m => m.MapKey(p => p.PersonId, “CustomFkToPersonId”));
将多对多表中的字段重新命名:
modelBuilder.Entity<Product>()
.HasMany(p => p.Tags)
.WithMany(t => t.Products)
.Map(m =>
{
m.MapLeftKey(p => p.ProductId, “CustomFkToProductId”);
m.MapRightKey(t => t.TagId, “CustomFkToTagId”);
});
表和字段映射
改变字段名:
modelBuilder.Entity<Category>()
.Property(c => c.Name)
.HasColumnName(“cat_name”);
改变表名:
modelBuilder.Entity<Category>()
.ToTable(“MyCategories”);
改变schema中的表名:
modelBuilder.Entity<Category>()
.ToTable(“MyCategories”, “sales”);
继承表映射
单表继承(Table Per Hierarchy,简称TPH)
TPH = “将所有的数据保存在一个表中,使用一个或多个字段的值来识别每行记录所属的类型”
简单的TPH是一个类继承层次结构的默认映射。
带自定义识别字段名称和值的TPH:
modelBuilder.Entity<Product>()
.Map<Product>(m => m.Requires(“Type”).HasValue(“Current”))
.Map<DiscontinuedProduct>(m => m.Requires(“Type”).HasValue(“Old”));
每个类型对应一个表(Table Per Type,简称TPT)
TPT = “将基类上属性的所有数据保存在单个表中,将继承类的任何额外数据保存在另外的表中,该表有一个指向基类表的外键”
modelBuilder.Entity<Product>().ToTable(“Products”);
modelBuilder.Entity<DiscontinuedProduct>().ToTable(“OldProducts”);
每个具体类对应一个表(Table Per Concrete Class, 简称TPC)
TPC = “为类层次结构的每个非抽象类型创建一个完全独立的表”
modelBuilder.Entity<Product>().ToTable(“Products”);
modelBuilder.Entity<DiscontinuedProduct>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable(“OldProducts”);
});
结语
在这个贴子里,我们看了若干个使用Code First 流畅 API的例子,在论坛上经常被问的场景会在以后添加进来。
反馈和支持
一如以往,我们非常希望你在这个博客贴子上做评论,给我们提供任何关于流畅API的反馈。
想得到支持的话,请使用实体框架预览产品论坛。
Rowan Miller
Program Manager
ADO.NET实体框架开发团队