EF6codefirst

本文介绍了EF6中的CodeFirst开发工作流程,包括通过域类配置创建数据库,详细阐述了如何安装EF实体框架,以及数据库初始化策略如CreateDatabaseIfNotExists等。此外,还详细讲解了数据注释属性和Fluent API在实体框架配置中的应用,如表、列、主键、外键的配置,并展示了如何设置一对一关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

精品不容错过!!!

EF6CodeFirst

什么是CodeFirst?

img

  • EF API通过域类配置创建数据库
  • 开发工作流程:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U5iZ4dfq-1617077584484)(https://www.entityframeworktutorial.net/images/codefirst/dev-workflow.png)]
  • 创建或者修改所需类——>使用流利的API或者数据注释属性配置这些类——>使用自动迁移或者基于代码的迁移创建或者更新数据库模式

安装EF实体框架

右键单击解决方案资源管理器中的项目,然后选择**“管理NuGet包”**,搜索Entity Framework

实体框架中的数据库初始化

  • 基于上下文类基本构造函数中传递的参数的数据库初始化流程,参数源自DBContext[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iOBp4XfS-1617077584485)(https://www.entityframeworktutorial.net/images/codefirst/database-init-fg1.PNG)]

  • 由上图可知,上下文基本构造器有以下参数

    1. 无参数
    2. 数据库名字
    3. 连接字符串的名称

    1.无参数:如果您没有指定上下文类基础构造器中的参数,则它会在您本地的 SQLEXPRESS 服务器中创建一个数据库,其名称与您的 {名称空间]相匹配,EF将创建SchoolDatalayer.Context的数据库

namespace SchoolDataLayer
{
public class Context: DbContext
{
public Context(): base()
{

      }
  }

}


2.数据库名称:如果您指定了数据库名称参数,则Code First 将创建一个数据库,其中包含您在本地 SQLEXPRESS 数据库服务器中指定的基础构造器中指定的名称,EF将创建MyschoolDB数据库

namespace SchoolDataLayer
{
public class Context: DbContext
{
public Context(): base(“MySchoolDB”)
{

      }
  }

}


3.连接串名称:以在应用.config 或 web.配置中定义连接字符串,并在上下文类的基本构造器中指定以"name+"开头的连接字符串名称

namespace SchoolDataLayer
{
public class Context: DbContext
{
public SchoolDBContext() : base(“name=SchoolDBConnectionString”)
{
}
}
}


应用配置为

```c#
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <connectionStrings>
    <add name="SchoolDBConnectionString" 
    connectionString="Data Source=.;Initial Catalog=SchoolDB-ByConnectionString;Integrated Security=true" 
    providerName="System.Data.SqlClient"/>
    </connectionStrings>
</configuration>

数据库初始化策略

有四种初始化策略:

  • CreateDatabaseIfNotExists

  • DropCreateDatabaseIfModelChanges(常用)

  • DropCreateDatabaseAlways

  • Custom DB Initializer(自定义初始化器)

①要使用初始化策略,可以使用以下的初始化器:

public class SchoolDBContext: DbContext 
{
    public SchoolDBContext(): base("SchoolDBConnectionString") 
    {
        Database.SetInitializer<SchoolDBContext>(new CreateDatabaseIfNotExists<SchoolDBContext>());

        //Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseIfModelChanges<SchoolDBContext>());
        //Database.SetInitializer<SchoolDBContext>(new DropCreateDatabaseAlways<SchoolDBContext>());
        //Database.SetInitializer<SchoolDBContext>(new SchoolDBInitializer());
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
}

Database.SetInitializer(null);//关闭数据初始化器

②可以通过继承其中一个初始化器创建自定义 DB 初始化器

public class SchoolDBInitializer :  CreateDatabaseIfNotExists<SchoolDBContext>
{
    protected override void Seed(SchoolDBContext context)
    {
        base.Seed(context);
    }
}
  

在配置文件中设置初始化器

默认初始化器

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>
    <add key="DatabaseInitializerForType SchoolDataLayer.SchoolDBContext, SchoolDataLayer"         
        value="System.Data.Entity.DropCreateDatabaseAlways`1[[SchoolDataLayer.SchoolDBContext, SchoolDataLayer]], EntityFramework" />
    </appSettings>
</configuration>

设置自定义数据库初始化器

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appSettings>    
    <add key="DatabaseInitializerForType SchoolDataLayer.SchoolDBContext, SchoolDataLayer"
            value="SchoolDataLayer.SchoolDBInitializer, SchoolDataLayer" />
    </appSettings>
</configuration>

实体框架配置域类

  1. 数据注释属性(Data Annotation Attributes)
  2. 流利的API(Fluent API)

数据注释属性

示例:

using System.ComponentModel.DataAnnotations.Schema;

[Table("StudentMaster", Schema="Admin")]
public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
}

[Table(string name, Properties:[Schema = string])

用于指定Student类生成的表名,持有者Adminimg

using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
     
    [Column("Name")]
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public byte[] Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
}

[Column (string name, Properties:[Order = int],[TypeName = string])

用于指定列在数据库中表的名字,索引,列的数据类型img

主键

覆盖默认以ID或者含有id为主键的约定

using System.ComponentModel.DataAnnotations;

public class Student
{
    [Key]
    [Column(Order=1)]
    public int StudentKey { get; set; }
     
    [Key]
    [Column(Order=2)]
    public int AdmissionNum { get; set; }
     
    public string StudentName { get; set; }
}

在EF6中,Colum该属性将在数据库中创建复合主键列

NotMapped

用于不想让该属性映射在数据库里,从而数据库不会为其创建列

EF 也不会为没有获取者或设置器的属性创建列,例如

public string City { get{ return StudentName;}  }
    public int Age { set{ _age = value;}  }
外键

[ForeignKey(name string)]

一个标准对应多个学生

using System.ComponentModel.DataAnnotations.Schema;

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
        
    [ForeignKey("Standard")]
    public int StandardRefId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public ICollection<Student> Students { get; set; }
}
InverseProperty

防止因为多个导航属性,EF无法确定关系的另一端,可以借用Foreignkey

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public string Description { get; set; }

    [ForeignKey("OnlineTeacher")]
    public int? OnlineTeacherId { get; set; }
    public Teacher OnlineTeacher { get; set; }

    [ForeignKey("ClassRoomTeacher")]
    public int? ClassRoomTeacherId { get; set; }
    public Teacher ClassRoomTeacher { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string Name { get; set; }

    [InverseProperty("OnlineTeacher")]
    public ICollection<Course> OnlineCourses { get; set; }
    [InverseProperty("ClassRoomTeacher")]
    public ICollection<Course> ClassRoomCourses { get; set; }
}
Required

要求必填

using System.ComponentModel.DataAnnotations;
    
public class Student
{
    public int StudentID { get; set; }
    [Required]
    public string StudentName { get; set; }
}
MaxLength(最大长)
StringLength(字符串长度)
Timestamp(时间戳)
DatabaseGenerated(数据库生成选项)

DatabaseGeneratedOption.None

  • 向 ID 属性(而不是数据库生成的值)提供自己的值,请使用这个选项

  • 数据库不生成值.

public class Course
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CourseId { get; set; }
    public string CourseName { get; set; }
}

DatabaseGeneratedOption.Identity

  • 可以使用该选项将非键(非 ID) 属性标记为 DB 生成的属性,让此属性无法更新

  • 数据库在插入行时生成值

    public class Course
    {
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int RecordNum { get; set; }
    }
    

DatabaseGeneratedOption.Computed

  • Computed选项只是告诉EF不要更新您的列,因为您将自己在DB端计算一个值.然后EF将从您的数据库中返回新计算的值(在您的情况下为“未设置”)

  • 数据库在插入或更新行时生成值

    public class Student
    {
        public int StudentID { get; set; }
        public string StudentName { get; set; }
        public DateTime? DateOfBirth { get; set; }
        public decimal Height { get; set; }
        public float Weight { get; set; }
    
        [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
        public DateTime CreatedDate { get; set; }
    } 
    
ConcurrencyCheck
  • 处理数据库数据级乐观并发,可以使用ConcurrencyCheck特性
  • Timestamp属性只能应用于单个字数阵列属性,而该属性可以应用于任何数据类型的任意数量的属性

Fluent API

DbModelBuilder类充当流利的 API,我们可以使用该类来配置许多不同的东西。它提供的配置选项多于数据注释属性。流利的 API 配置了实体框架 6 中模型的以下方面:

  1. 全模型配置:配置默认的 Schema、映射中要排除的实体等。

  2. 实体配置:将实体配置为表和关系映射,例如主键、索引、表名称、一对一、一对多、多对多等。

  3. 属性配置:将属性配置为列映射,例如列名称、可用性、外键、数据类型、并发列等。

    常用的Fluent API方法
    配置 Fluent API方法 作用
    架构相关配置 HasDefaultSchema() 数据库的默认架构
    ComplexType() 把一个类配置为复杂类型
    实体相关配置 HasIndex() 实体的的索引
    HasKey() 实体的主键(可其实现复合主键,[Key]在EF core中不能实现复合主键)
    HasMany() 1对多的或者 多对多关系
    HasOptional() 一个可选的关系,这样配置会在数据库中生成一个可空的外键
    HasRequired() 一个必有的关系,这样配置会在数据库中生成一个不能为空的外键
    Ignore() 实体或者实体的属性不映射到数据库
    Map() 设置一些优先的配置
    MapToStoredProcedures() 实体的CUD操作使用存储过程
    ToTable() 为实体设置表名
    属性相关配置 HasColumnAnnotation() 给属性设置注释
    IsRequired() 在调用SaveChanges()方法时,属性不能为空
    IsOptional() 可选的,在数据库生成可空的列
    HasParameterName() 配置用于该属性的存储过程的参数名
    HasDatabaseGeneratedOption() 配置数据库中对应列的值怎样生成的,如计算,自增等
    HasColumnOrder() 配置数据库中对应列的排列顺序
    HasColumnType() 配置数据库中对应列的数据类型
    HasColumnName() 配置数据库中对应列的列名
    IsConcurrencyToken() 配置数据库中对应列用于乐观并发检测
    注:不用全部了解,要用的时候网上查就行

  • 设置主键
    modelBuilder.Entity().HasKey(t => t.Name);

  • 设置联合主键
    modelBuilder.Entity().HasKey(t =>new{t.Name,t.ID} );

  • 取消数据库字段标识(取消自动增长)
    modelBuilder.Entity().Property(t=>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

  • 设置数据库字段标识(自动增长)
    modelBuilder.Entity().Property(t =>t.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

  • 设置字段最大长度
    modelBuilder.Entity().Property(t => t.Name).HasMaxLength(100);

  • 设置字段为必需
    modelBuilder.Entity().Property(t =>t.Id).IsRequired();

  • 属性不映射到数据库
    modelBuilder.Entity().Ignore(t => t.A);

  • 将属性指定数据库列名:
    modelBuilder.Entity() .Property(t => t.A) .HasColumnName(“A_a”);

  • 级联删除(数据库默认是不级联删除的)
    modelBuilder.Entity().HasRequired(t => t.Department).WithMany(t => t.Courses).HasForeignKey(d => d.DepartmentID).WillCascadeOnDelete();

  • 设置为Timestamp
    modelBuilder.Entity() .Property(t => t.Timestamp) .IsRowVersion();

  • 表1对0…1(Instructor实体可以包含零个或一个OfficeAssignment)
    modelBuilder.Entity().HasRequired(t => t.Instructor).WithOptional(t => t.OfficeAssignment);

  • 表1对1
    modelBuilder.Entity().HasRequired(t => t.OfficeAssignment).WithRequiredPrincipal(t => t.Instructor);

  • 表1对n(Department为主表)
    modelBuilder.Entity() .HasRequired(c => c.Department) .WithMany(t => t.Staffs)

  • 指定外键名(指定表Staff中的字段DepartmentID为外键)
    modelBuilder.Entity() .HasRequired(c => c.Department) .WithMany(t => t.Staffs) .Map(m => m.MapKey(“DepartmentID”));

  • 表n对n
    modelBuilder.Entity()
    .HasMany(t => t.Instructors)
    .WithMany(t => t.Courses)

  • 表n对n指定连接表名及列名
    modelBuilder.Entity()
    .HasMany(t => t.Instructors)
    .WithMany(t => t.Courses)
    .Map(m =>
    {
    m.ToTable(“CourseInstructor”);
    m.MapLeftKey(“CourseID”);
    m.MapRightKey(“InstructorID”);
    });

实体映射
配置默认模式为管理员模式
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure default schema
        modelBuilder.HasDefaultSchema("Admin");
    }
}
将实体映射到表,设置表名
namespace CodeFirst_FluentAPI_Tutorials
{
    public class SchoolContext: DbContext 
    {
        public SchoolDBContext(): base() 
        {
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //Configure default schema
            modelBuilder.HasDefaultSchema("Admin");
                    
            //Map entity to table
            modelBuilder.Entity<Student>().ToTable("StudentInfo");
            modelBuilder.Entity<Standard>().ToTable("StandardInfo","dbo");
        }
    }
}
实体映射到数据库中的多个表
namespace CodeFirst_FluentAPI_Tutorials
{
    public class SchoolContext: DbContext 
    {
        public SchoolDBContext(): base() 
        {
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>().Map(m =>
            {
                m.Properties(p => new { p.StudentId, p.StudentName});
                m.ToTable("StudentInfo");
            }).Map(m => {
                m.Properties(p => new { p.StudentId, p.Height, p.Weight, p.Photo, p.DateOfBirth});
                m.ToTable("StudentInfoDetail");
            });

            modelBuilder.Entity<Standard>().ToTable("StandardInfo");
        }
    }
}
属性映射

使用流利的 API,您可以更改相应的列名称、类型、大小、空或否、主键、外键、并发列等

配置主键和复合主键
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure primary key
        modelBuilder.Entity<Student>().HasKey<int>(s => s.StudentKey);
        modelBuilder.Entity<Standard>().HasKey<int>(s => s.StandardKey);

        //Configure composite primary key  复合主键
        modelBuilder.Entity<Student>().HasKey<int>(s => new { s.StudentKey, s.StudentName }); 
    }
}
    
配置列名称、类型和顺序
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Configure Column
        modelBuilder.Entity<Student>()
                    .Property(p => p.DateOfBirth)//指定哪列
                    .HasColumnName("DoB")//列名
                    .HasColumnOrder(3)//对应列的排列顺序
                    .HasColumnType("datetime2");//对应列的数据类型
    }
}
配置可不可空
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
            //Configure Null Column
        modelBuilder.Entity<Student>()
                .Property(p => p.Heigth)
                .IsOptional();//可空
                        
            //Configure NotNull Column
            modelBuilder.Entity<Student>()
                .Property(p => p.Weight)
                .IsRequired();//不可空
    }
}
配置列长
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName column size to 50
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50);
                        
        //Set StudentName column size to 50 and change datatype to nchar 
        //IsFixedLength() change datatype from nvarchar to nchar
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .HasMaxLength(50).IsFixedLength();
                        
        //Set size decimal(2,2)
            modelBuilder.Entity<Student>()
                .Property(p => p.Height)
                .HasPrecision(2, 2);
    }
}

我们使用HasMaxLength()方法配置列的大小,IsFixedLength()方法会将列的类型从nvarchar转到nchar.HasPrecision()可以配置decimal数据类型的属性的精度。

配置并发列
public class SchoolContext: DbContext 
{
    public SchoolDBContext(): base() 
    {
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Standard> Standards { get; set; }
        
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //Set StudentName as concurrency column
        modelBuilder.Entity<Student>()
                .Property(p => p.StudentName)
                .IsConcurrencyToken();
    }
}

StudentName列是并发列,所以更新和删除的时候,这个列名将会在where子句中。
你同样可以使用IsRowVersion()来配置并发列,只不过这个IsRowVersion()只能用在byte[]数组类型的属性上。

配置一对一

使用数据注释属性配置一对零或一关系

当一个表的主键在关系数据库(如 SQL 服务器)中成为另一个表中的 PK 和 FK 时,就会发生一对零或一关系。

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual StudentAddress Address { get; set; }
}
     
public class StudentAddress 
{
    [ForeignKey("Student")]
    public int StudentAddressId { get; set; }
        
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public int Zipcode { get; set; }
    public string State { get; set; }
    public string Country { get; set; }

    public virtual Student Student { get; set; }
}

使用流利的 API 配置一对零或一关系

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure Student & StudentAddress entity
    modelBuilder.Entity<Student>()
                .HasOptional(s => s.Address) // Mark Address property optional in Student entity
                .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student

未完待续…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值