• Entity Framework Code First属性映射约定


      Entity Framework Code First与数据表之间的映射方式有两种实现:Data Annotation和Fluent API。本文中采用创建Product类为例来说明tity Framework Code First属性映射约定的具体方式。

    1. 表名及所有者

      在默认约定的情况下,Entity Framework Code First创建的表名是根据类名的英语复数形式,创建的表所有者为dbo,可以通过重写约定来指定表名及表的所有者。

    1.1 Data Annotation方式

      在使用Data Annotation方式进行Entity Framework Code First与数据库映射之前,需要先添加命名空间引用。

    using System.ComponentModel.DataAnnotations.Schema;

      为类配置对应表名:

    [Table("Product")]
    public class Product

      为类配置对应表名并指定表的所有者:

    [Table("Product", Schema = "dbo")]
    public class Product

    1.2 Fluent API方式

      Fluent API实现配置Entity Framework Code First与数据库映射关系主要是通过继承DbContext并重写其中的OnModelCreating方法来进行的。在本文中新建类文件PortalContext.cs继承DbContext。

      在继承DbContext之前,添加命名空间引用。

    using System.Data.Entity;

      重写OnModelCreating方法,配置类对应于数据库中的表名:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().ToTable("Product");
    }

      重写OnModelCreating方法,配置类对应于数据库中的表名,并指定表的所有者:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().ToTable("Product", "dbo");
    }

      到此处PortalContext.cs的完整代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using System.Data.Entity;
    
    using Portal.Entities;
    
    namespace Portal
    {
        public class PortalContext : DbContext
        {
            static PortalContext()
            {
                Database.SetInitializer(new DropCreateDatabaseIfModelChanges<PortalContext>());
            }
    
            public PortalContext()
                : base("name=PortalContext")
            {
            }
    
            public DbSet<Product> Products { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Product>().ToTable("Product", "dbo");
            }
        }
    }
    View Code

    2. 字段名、长度、数据类型及是否可空

      在默认约定的情况下,Entity Framework Code First创建的列名与类的属性名相同,可以根据需要进行重新指定类属性与列名之间的映射关系。

    2.1 Data Annotation方式

    [Column("ProductID")]
    public int ProductID { get; set; }

    [MaxLength(100)] [Required, Column(
    "ProductName")] public string ProductName { get; set; }

      在使用Required特性(Attribute)设置字段不允许为空时,需要添加命名空间引用:

    using System.ComponentModel.DataAnnotations;

    1.2 Fluent API方式

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().Property(t => t.ProductID)
            .HasColumnName("ProductID");
        modelBuilder.Entity<Product>().Property(t => t.ProductName)
            .IsRequired()
            .HasColumnName("ProductName")
         .HasMaxLength(100); }

      在默认情况下,int类型的属性生成的列名对应SQL SERVER列int类型;而String类型的属性则对应SQL SERVER列的NVARCHAR类型。若类的字符串类型属性未设置MaxLength,则生成对应的列类型为NVARCHAR(MAX)。

      为属性指定对应的SQL SERVER数据类型:

    [Column("UnitPrice", TypeName = "MONEY")]
    public decimal UnitPrice { get; set; }
    modelBuilder.Entity<Product>().Property(t => t.UnitPrice)
        .HasColumnName("UnitPrice")
        .HasColumnType("MONEY");

      到此步,Product.cs类文件的完整代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace Portal.Entities
    {
        [Table("Product", Schema = "dbo")]
        public class Product
        {
            [Column("ProductID")]
            public int ProductID { get; set; }
    
            [MaxLength(100)]
            [Required, Column("ProductName")]
            public string ProductName { get; set; }
    
            [Column("UnitPrice", TypeName = "MONEY")]
            public decimal UnitPrice { get; set; }
        }
    }
    View Code

      属性设置text数据类型:

    [Column("Remark", TypeName = "text")]
    public string Remark { get; set; }
    modelBuilder.Entity<Category>().Property(t => t.Remark)
        .HasColumnName("Remark")
        .HasColumnType("text");

    3. 主键

      Entity Framework Code First的默认主键约束:属性名为[ID]或[类名 + ID]。如在Product类中,Entity Framework Code First会根据默认约定将类中名称为ID或ProductID的属性设置为主键。Entity Framework Code First主键的默认约定也一样可以进行重写,重新根据需要进行设置。

    3.1 Data Annotation方式

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    [Key]
    [Column("ProductID")]
    public int ProductID { get; set; }

    3.2 Fluent API方式

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasKey(t => t.ProductID);
    }

      若一个表有多个主键时:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasKey(t => new { t.KeyID, t.CandidateID });
    }

    4、数据库自动生成字段值

      Entity Framework Code First对于int类型的主键,会自动的设置其为自动增长列。但有时我们确实不需是自动增长的,可以通过以下方式进行取消自动增长。

    4.1 Data Annotation方式

    [Key]
    [Column("ProductID")]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int ProductID { get; set; }
    [Key]
    [Column("CategoryID")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CategoryID { get; set; }

    4.2 Fluent API方式

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasKey(t => t.ProductID);
        modelBuilder.Entity<Product>().Property(t => t.ProductID)
            .HasColumnName("ProductID")
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Category>().ToTable("Category", "dbo");
        modelBuilder.Entity<Category>().HasKey(t => t.CategoryID);
        modelBuilder.Entity<Category>().Property(t => t.CategoryID)
            .HasColumnName("CategoryID")
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }

    5. 数字类型长度及精度

      在Product类中,UnitPrice表示单价,对于价格类的字段,我们通常会希望其保留2为小数。这时可以使用Fluent API进行设置,且Data Annotation不支持该设置。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().Property(t => t.UnitPrice)
            .HasColumnName("UnitPrice")
            .HasPrecision(18, 2);
    }

    6、非数据库字段属性

      在类中,如果有一些属性不需要映射到对应生成的数据表中,可以通过以下方式设置。

    6.1 Data Annotation方式

    [NotMapped]
    public string Remark { get; set; }

    6.2 Fluent API方式

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().Ignore(t => t.Remark);
    }

    7. Fluent API配置Configuration映射类

      在使用Fluent API进行Entity Framework Code First数据库映射时,除了以上的在重写OnModelCreating方法中直接对Entity进行配置之外,也可以对Configurations进行配置。这时可以先写一个单独的类,将数据表的全部映射要求都写在构造函数中。

      ProductMap.cs类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.ModelConfiguration;
    
    using Portal.Entities;
    
    namespace Portal.Mapping
    {
        public class ProductMap : EntityTypeConfiguration<Product>
        {
            public ProductMap()
            {
                // Primary Key
                this.HasKey(t => t.ProductID);
    
                // Properties
                this.Property(t => t.ProductID)
                    .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
                this.Property(t => t.ProductName)
                    .IsRequired()
                    .HasMaxLength(100);
    
                // Table & Column Mappings
                this.ToTable("Product");
                this.Property(t => t.ProductID).HasColumnName("ProductID");
                this.Property(t => t.ProductName).HasColumnName("ProductName");
                this.Property(t => t.UnitPrice)
                    .HasColumnName("UnitPrice")
                    .HasPrecision(18, 2);
            }
        }
    }

      有了上面的映射类之后,在重写OnModelCreating方法中则可以直接调用映射类,从而减少了OnModelCreating方法的复杂度,同时也增强了代码维护的可读性。

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new ProductMap());
    }
  • 相关阅读:
    YOLO V5 is Here! Custom Object Detection Tutorial with YOLO V5
    pjsip application notes
    Tilt Angle Visualization With Edison, Accelerometer and Python
    WebRTC 镜像源
    Get Started with WebRTC
    sqlserver关于发布订阅replication_subscription的总结
    在Flask中,g是什么?它的生命周期是?能做什么?
    46.全排列问题
    【LeetCode】代码模板,刷题必会
    QEMU+KVM学习笔记
  • 原文地址:https://www.cnblogs.com/libingql/p/3352058.html
Copyright © 2020-2023  润新知