Entity Framework 5.0 Code First全面学习

本文深入探讨了Entity Framework 5.0的Code First开发方式,介绍了各种约定,如类型发现、主键、关系、连接字符串等。此外,文章还讨论了数据注释和Fluent API的使用,以及数据库初始化策略,如种子数据的添加。通过示例代码,解释了如何配置和管理数据库关系,包括外键、级联删除和导航属性。最后,讨论了预加载、惰性加载、显式加载等多种数据加载策略,以及如何利用DbContext执行原始SQL查询。
摘要由CSDN通过智能技术生成

不贴图片了,太累。

Code First 约定

借助 CodeFirst,可通过使用 C# 或Visual Basic .NET 类来描述模型。模型的基本形状可通过约定来检测。约定是规则集,用于在使用 Code First 时基于类定义自动配置概念模型。约定是在 System.Data.Entity.ModelConfiguration.Conventions 命名空间中定义的。

可通过使用数据注释或Fluent API 进一步配置模型。优先级是通过 Fluent API 进行配置,然后是通过数据注释,再次是通过约定。

API 文档中提供了 Code First 约定的详细列表。本主题概述 Code First 使用的约定。

类型发现

当使用 CodeFirst 开发时,通常是从编写用来定义概念(域)模型的 .NET类开始。除了定义类之外,还需要让 DbContext 知道模型中要包含哪些类。为此,需要定义一个上下文类,此类派生自 DbContext 并公开需要成为模型一部分的类型的 DbSet 属性。Code First 将包含这些类型,还将包含任何引用类型,即使这些引用类型是在不同的程序集中定义的也是如此。

如果类型存在于继承层次结构中,则为基类定义 DbSet 属性就足够了,如果派生类型位于与基类相同的程序集中,则自动包含这些派生类型。

在下面的示例中,仅对SchoolEntities 类定义一个DbSet 属性 (Departments)。CodeFirst 使用此属性来发现并包含任何引用类型。

publicclass SchoolEntities: DbContext

{

  public DbSet<Department>Departments { get; set;}

}

 

publicclass Department

{

  // Primary key

  public int DepartmentID { get;set; }

  public string Name { get; set; }

 

  // Navigationproperty

  public virtual ICollection<Course> Courses { get;set; }

}

 

publicclass Course

{

  // Primary key

  public int CourseID { get; set; }

 

  public string Title { get; set; }

  public int Credits { get; set; }

 

  // Foreign key

  public int DepartmentID { get;set; }

 

  // Navigationproperties

  public virtual DepartmentDepartment { get; set;}

}

 

publicpartial class OnlineCourse : Course

{

  public string URL { get; set; }

}

 

publicpartial class OnsiteCourse : Course

{

  public string Location { get;set; }

  public string Days { get; set; }

  publicSystem.DateTime Time { get; set; }

}

如果要从模型排除类型,请使用 NotMapped 特性或DbModelBuilder.Ignore

主键约定

如果类的属性名为“ID”(不区分大小写)或类名的后面跟有“ID”,则 Code First 会推断该属性是主键。如果主键属性的类型为数值或 GUID,则将其配置为标识列。

publicclass Department

{

  // Primary key

  public int DepartmentID { get;set; }

}

 

关系约定

实体框架中的导航属性提供了一种在两个实体类型之间导航关系的方法。针对对象参与到其中的每个关系,各对象均可以具有导航属性。使用导航属性,可以在两个方向上导航和管理关系,返回引用对象(如果多重性为一或者零或一)或集合(如果多重性为多)。Code First 根据针对类型定义的导航属性来推断关系。

除导航属性外,建议还要包括表示依赖对象的类型的外键属性。任何数据类型与主体主键属性相同、遵循以下一种格式的属性都表示关系的外键:“<导航属性名称><主体主键属性>”、“<主体类名><主键属性名称>”或“<主体主键属性名称>”。如果找到多个匹配项,则优先级符合上面列出的顺序。外键检测不区分大小写。在检测外键属性时,Code First 基于外键的可空性推断关系的多重性。如果属性可以为 Null,则将关系注册为可选关系;否则,将关系注册为必需关系。

如果依赖实体上的外键不能为 Null,则 CodeFirst 对关系设置级联删除。如果依赖实体上的外键可以为 Null,则Code First 不对关系设置级联删除,并且在删除主体时,会将该外键设置为 Null。通过使用 Fluent API,可以覆盖由约定检测的多重性和级联删除行为。

publicclass Department

{

  // Primary key

  public int DepartmentID { get;set; }

  public string Name { get; set; }

 

  // Navigationproperty

  public virtual ICollection<Course> Courses { get;set; }

}

 

publicclass Course

{

  // Primary key

  public int CourseID { get; set; }

 

  public string Title { get; set; }

  public int Credits { get; set; }

 

  // Foreign key

  public int DepartmentID { get;set; }

 

  // Navigationproperties

  public virtual DepartmentDepartment { get; set;}

}

 

在下面的示例中,导航属性和外键用于定义 Department 类与Course 类之间的关系。

注意:如果相同类型间有多个关系(例如,假设定义 Person 和Book 类,其中,Person 包含ReviewedBooks 和AuthoredBooks 导航属性,而Book 类包含 Author 和Reviewer 导航属性),则需要使用数据注释或 Fluent API 手动配置关系。

复杂类型约定

当 CodeFirst 发现无法推断主键以及未通过数据注释或 Fluent API 注册主键的类时,类型会自动注册为复杂类型。复杂类型检测还要求类型不具有引用实体类型的属性,并且未被其他类型的集合属性引用。对于以下类定义,Code First 推断Details 是复杂类型,因为它没有主键。

publicpartial class OnsiteCourse : Course

{

  publicOnsiteCourse()

  {

    Details = newDetails();

  }

 

  public Details Details { get;set; }

}

 

publicclass Details

{

  publicSystem.DateTime Time { get; set; }

  public string Location { get;set; }

  public string Days { get; set; }

}

 

连接字符串约定

默认配置

如果您还没有在应用程序中进行任何其他配置,则对 DbContext 调用无参数构造函数将会导致 DbContext 使用按约定创建的数据库连接在 Code First 模式下运行。例如:

namespaceDemo.EF

{

  public class BloggingContext: DbContext

  {

    publicBloggingContext()

    // C# will callbase class parameterless constructor by default

    {

    }

  }

}

在此示例中,DbContext使用派生上下文类 Demo.EF.BloggingContext 的命名空间限定名称作为数据库名称,并使用 SQL Express 或 LocalDb 为此数据库创建连接字符串。如果同时安装了这两个数据库,将使用 SQL Express。

默认情况下,VisualStudio 2010 包含 SQLExpress,VisualStudio 2012 包含LocalDb。安装期间,EntityFrameworkNuGet 包会检查哪个数据库服务器可用。随后 NuGet 包将设置按约定创建连接时 Code First 所使用的默认数据库服务器,以此更新配置文件。如果 SQL Express 正在运行,将使用它。如果 SQL Express 不可用,则 LocalDb 将注册为默认数据库。如果配置文件已包含默认连接工厂设置,则不会更改该文件。

指定数据库名称

如果您尚未在应用程序中进行任何其他配置,在通过要使用的数据库名称对 DbContext 调用字符串构造函数时,将会导致 DbContext 使用按约定创建的与该名称数据库的连接在 Code First 模式下运行。例如:

namespaceDemo.EF

{

  public class BloggingContext: DbContext

  {

    public BloggingContext()

      : base("BloggingDatabase")

    {

    }

  }

}

在此示例中,DbContext使用“BloggingDatabase”作为数据库名称,并使用 SQL Express(随Visual Studio 2010 安装)或LocalDb(随Visual Studio 2012 安装)为此数据库创建连接字符串。如果同时安装了这两个数据库,将使用 SQL Express。

指定连接字符串

可以选择将连接字符串放入 app.config 或web.config 文件中。例如:

<configuration>

  <connectionStrings>

    <addname="BloggingCompactDatabase"

         providerName="System.Data.SqlServerCe.4.0"

         connectionString="Data Source=Blogging.sdf"/>

  </connectionStrings>

</configuration>

这是一种指示 DbContext 使用数据库服务器而非 SQL Express 或LocalDb 的简单方法 — 上例指定了 SQL Server Compact Edition 数据库。

如果连接字符串的名称与上下文的名称(带或不带命名空间限定)相同,则使用无参数构造函数时 DbContext 会找到该连接字符串。如果连接字符串名称与上下文名称不同,则可通过将连接字符串名称传递给 DbContext 构造函数,指示 DbContext 在 CodeFirst 模式下使用此连接。例如:

publicclass BloggingContext: DbContext

{

  publicBloggingContext()

    : base("BloggingCompactDatabase")

  {

  }

}

或者,也可以对传递给DbContext 构造函数的字符串使用 “name=<连接字符串名称>”格式。例如:

publicclass BloggingContext: DbContext

{

  publicBloggingContext()

    : base("name=BloggingCompactDatabase")

  {

  }

}

使用此形式可以明确要求在配置文件中查找连接字符串。如果未找到具有给定名称的连接字符串,则将引发异常。

数据库初始化策略:

数据库创建是由策略来控制的,有如下四种策略:

1.       CreateDatabaseIfNotExists:这是默认的策略。如果数据库不存在,那么就创建数据库。但是如果数据库存在了,而且实体发生了变化,就会出现异常。

2.       DropCreateDatabaseIfModelChanges:此策略表明,如果模型变化了,数据库就会被重新创建,原来的数据库被删除掉了。

3.       DropCreateDatabaseAlways:此策略表示,每次运行程序都会重新创建数据库,这在开发和调试的时候非常有用。

4.       自定制数据库策略:可以自己实现IDatabaseInitializer来创建自己的策略。或者从已有的实现了IDatabaseInitializer接口的类派生。

如下示例显示了如何应用数据库创建策略:

public class UserManContext : DbContext

{

    public UserManContext()

        : base("USMDBConnectionString")

    {           

        Database.SetInitializer<UserManContext>(new CreateDatabaseIfNotExists<UserManContext>());

    }   

}

下面的代码创建了一个自定义策略,什么也没有做,但是我们可以在Seed方法里添加我们的种子数据。

public class USMDBInitializer : <

  • 5
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值