Entity Framwork CodeFirst 学习笔记二:约定和配置

对EF Code first 编程模型有了一定的了解之后,通过上一篇简单的例子,通过代码对数据库进行了创建,但是其数据结构都是按照EF默认的约定来创建的。比如:

数据库名称:由于上一篇的例子在配置文件中显示设置数据库的连接,因此创建的数据库名称就为连接串中指定的 BookDb。若没有显示指定的话,并使用默认数据库 .\SQLEXPRESS, 则EF生成的数据库名称应该为DbContext 的"命名空间.类名" (DataAccess.BookContext)

表名:默认约定均为模型类名的复数形式。如例子中的 AuthorsBooks ,没有指定架构名称则采用默认架构名:dbo

数据类型:字符串类型默认映射成nvarchar(max),byte[] 数组类型默认映射成varbinary(max),bool类型默认映射成bit,decimal类型默认映射成decimal(18, 2),float类型默认映射成float。由于bool,decimal,float等是值类型,不能为给他们分配Null值。因此生成的数据库会要求对应的列非空。 

外键:codefirst 会自动检测模型间的关系,比如我们的实体类中Author 有 List<Books> 属性,Book类中还有 Author 属性,则说明 Author 和Book 是 1对多的关系,EF中外键的命名默认是导航属性名(这里是Author_对应主表的主键)由于我们有了AuthorId ,因此就AuthorId 就默认为外键。

上一篇的例子均是采用EF Code First 的默认配置,下面我们来对这些配置进行修改,有两种方式可以打破默认的配置规则:

  • Data Annotations (需引用System.ComponentModel.DataAnnotations),直接作用于类的属性上面。
  • 利用FluntAPI,通过增加相应的配置类来覆盖默认配置。

如果使用FluntAPI,需要在上下文类中增加如下方法:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     //这里增加配置代码

      base.OnModelCreating(modelBuilder);
}

 注意 FluntAPI 优先于 Data Annotations 配置。

在《Programming Entity Framework Code First》 这本书中将 配置约定分别分为了三个章节,分别是属性配置、关系配置和数据库映射配置。下面分别对常用的配置做一下总结:

1、表名及架构名:(不指定架构名,则默认为dbo)

Data Annotations 方式:[Table]

[Table("T_Author", Schema = "Lx")]
 public class Author
 {
    public int AuthorId { get; set; }
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
    public byte[] Photo { get; set; }
    public string Introduce { get; set; }
    public List<Book> MyBooks { get; set; }
 }

Flunt API 方式:

modelBuilder.Entity<Author>().ToTable("T_Author", "Lx");

  2、字段名:

Data Annotations 方式:[Column]

[Column("AuthorName")]
public string Name { get; set; }

Flunt API 方式:

modelBuilder.Entity<Author>().Property(a => a.Name).HasColumnName("AuthorName");

 3、主键:

Data Annotations 方式:[Key] 

[Key]
public int AuthorId { get; set; }

 Flunt API 方式:

modelBuilder.Entity<Author>().HasKey(a=>a.AuthorId);

 4、外键:

Data Annotations 方式:[ForeignKey] 

public int AuthorId { get; set; }
[ForeignKey("AuthorId")]
public Author Author { get; set; }

 注意:如果ForeignKey中指定了列名 ,如“AuthorId ”则类中必须存在 AuthorId 属性

Flunt API 方式:

 modelBuilder.Entity<Book>().HasRequired(b => b.Author).WithMany(a => a.MyBooks).HasForeignKey(b => b.AuthorId);

 5、设置自动增长属性  

利用数据生成项 DatabaseGenerated,它后有三个枚举值: Identity:自增长;None:不处理;Computed:表示这一列是计算列

注意:在EF中,如果主键是int类型,Code First生成数据库的时候会自动设置该列为自增长。但如果主键是Guid类型,需要手动去设置 

DATA Annotations 方式:[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 

[Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AuthorId { get; set; }

 Flunt API 方式: 

modelBuilder.Entity<Author>().HasKey(a => a.AuthorId).Property(a => a.AuthorId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

  关于 DatabaseGenerated 后面的文章要详细的学习

6、忽略映射

对于不需要映射的表或者列,我们可以忽略映射

Data Annotations 方式:[NotMapped] 

//忽略表映射
[NotMapped]
public class Book
{
   public int BookId { get; set; }
   public string BookName { get; set; }
   public decimal Price { get; set; }
   public bool IsSellFast { get; set; }
   public int AuthorId { get; set; }
   public Author Author { get; set; }
}
//忽略列映射
[NotMapped]
public bool IsSellFast { get; set; }

 Flunt API 方式:

//忽略表映射
modelBuilder.Ignore<Book>();
//忽略列映射
modelBuilder.Entity<Book>().Ignore(b => b.IsSellFast);

 7、非空属性及错误提示信息

Data Annotations 方式:[Required]  OR [Required(ErrorMessage = "xxx")] 

[Required]
public string BookName { get; set; }

[Required(ErrorMessage = "请输入价格")]
public decimal Price { get; set; }

 Flunt API 方式: 

modelBuilder.Entity<Book>().Property(b => b.BookName).IsRequired();

 8、长度:

Data Annotations 方式:[StringLength] 表示长度;[MinLength]表示最小长度;[MaxLength]表示最大长度

[StringLength(10)]
public string Name { get; set; }
[MinLength(20), MaxLength(200)]
public string Introduce { get; set; }

 Flunt API 方式 (Flunt Api 方式没有设置 MinLength 这个方法,长度及最大长度都用HasMaxLength 方式)

modelBuilder.Entity<Author>().Property(a => a.Name).HasMaxLength(10);

 9、配置类型:

Data Annotations 方式:[Column(TypeName="")]

[Column(TypeName = "image")]
public byte[] Photo { get; set; }

 Flunt API 方式 :

modelBuilder.Entity<Book>().Property(b => b.Price).HasColumnType("image");

 10、防止并发:

(1)对表做并发处理:

 Data Annotations 方式:[Timestamp]

注意:如果要对某一个表做并发处理,就在该表中加一条Timestamp类型的字段,但是这个字段必须为byte[]类型,并且一个类中只能存在一个。

[Timestamp]
public byte[] RowVersion { get; set; }

 Flunt API 方式 : 

modelBuilder.Entity<Book>().Property(b => b.RowVersion).IsRowVersion();

 (2)对某个字段作并发控制:

Data Annotations 方式:[ConcurrencyCheck]

[ConcurrencyCheck]
public string BookName { get; set; }

  Flunt API 方式 :

modelBuilder.Entity<Book>().Property(b => b.BookName).IsConcurrencyToken();

关于 并发控制 后面的文章要详细的学习

 10、复杂类型

Data Annotations 方式:[ComplexType]

[ComplexType]
public class Address
{
  public int AddressId { get; set; }
  public string StreetAddress { get; set; }
  public string City { get; set; }
  public string State { get; set; }
  public string ZipCode { get; set; }
}

 Flunt API 方式 : 

modelBuilder.ComplexType<Address>();

 关于 复杂类型 后面的文章要详细的学习

这里只列举和记录了 10 种配置方式,具体参见: http://msdn.microsoft.com/zh-cn/library/system.componentmodel.dataannotations.aspx

下面把先前的例子的某些配置整理一下:

Data Annotations 方式:

    //设置Author 类 映射表名为 T_Author,架构名为 Lx
    [Table("T_Author",Schema="Lx")]
    public class Author
    {       
        [Column("AuthorId",TypeName="int")]
        public int AuthorId { get; set; }

        //修改Name属性 映射为 AuthorName
        //长度 10
        [Column("AuthorName",TypeName="nvarchar")]
        [Required,StringLength(10)]
        public string Name { get; set; }
                
        //设置Birthday 可空
        public DateTime? Birthday { get; set; }

        //设置 Photo 属性 映射类型 为 image
        [Column(TypeName = "image")]
        public byte[] Photo { get; set; }

        //设置 Introduce 属性最小长度 20,最大长度 100
        [MinLength(20),MaxLength(100)]
        public string Introduce { get; set; }

        public List<Book> MyBooks { get; set; }
    }

    //设置 Book 类 映射表名为 T_Books,架构名为 Lx
    [Table("T_Books", Schema = "Lx")]
    public class Book
    {
        // BookId 为主键且自增
        [Key]
        public int BookId { get; set; }
        
        public int AuthorId { get; set; }
        
        //设置 BookName 属性 不能为空,字段长度为 50
        [Required,StringLength(50)]
        public string BookName { get; set; }
        
        //DataAnnotation 方式不能控制deciaml 的精度
        //默认为(18,2)
        public decimal Price { get; set; }

        public bool IsSellFast { get; set; }

        //设置外键为 AuthorId
        [ForeignKey("AuthorId")]
        public Author Author { get; set; }
    }

  Flunt API 方式 :

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

   //设置 Author 表名 T_Author 架构名 Lx
   modelBuilder.Entity<Author>().ToTable("T_Authors", "Lx");

   //设置 Name 属性 非空,映射为列名 AuthorName,长度 10
   modelBuilder.Entity<Author>().Property(a => a.Name).IsRequired()
                                 .HasColumnName("AuthorName")
                                 .HasMaxLength(10);

   //设置 photo 属性 映射类型为 image
   modelBuilder.Entity<Author>().Property(a => a.Photo).HasColumnType("image");

   //Flunt Api 无法设置最小长度
   modelBuilder.Entity<Author>().Property(a => a.Introduce).HasMaxLength(100);


   //设置 Book 表名 T_Books 架构名 Lx
   modelBuilder.Entity<Book>().ToTable("T_Books", "Lx");

   //设置 BookId 为主键且自动增长
   modelBuilder.Entity<Book>().HasKey(b => b.BookId)
                                       .Property(b => b.BookId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

   //设置 AuthorId 为外键
   modelBuilder.Entity<Book>().HasRequired(b => b.Author).WithMany(a => a.MyBooks).HasForeignKey(b => b.AuthorId);

//设置 BookName 属性不能为空,字符串长度 50 modelBuilder.Entity<Book>().Property(b => b.BookName).IsRequired() .HasMaxLength(50); //FluntAPI 可以设置 decimal 类型的精度 modelBuilder.Entity<Book>().Property(b => b.Price).HasColumnType("decimal").HasPrecision(3, 1);
}

 运行程序,结果如下图:

--=源码下载=--

posted @ 2013-05-17 17:22  Rising_Sun  阅读(2042)  评论(1编辑  收藏  举报