zoukankan      html  css  js  c++  java
  • [ORM] Entity Framework(2) CodeFirst进阶

        在上一节中,实现了CodeFirst快速入门。但是很多与数据库的细节还无法自定义。以及使用EF过程中,需要注意的事项。

        在本节中,会涉及到以下

    连接字符串

      1个完整的连接字符串  IP:端口实例名 数据库名组成

      Nuget安装完EF会在*.config的entityFramework节点下添加,表示使用LocalDb数据库,实例名为v11.0。

    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
          <parameters>
            <parameter value="v11.0" />
          </parameters>
    </defaultConnectionFactory>

      而数据库名,默认为类的全限定名。如下调用父类构造函数,表示数据库名为SaleDb。而不是命名空间+类名。

        public class SaleDb : DbContext
        {
            public SaleDb():base("SaleDb")
            {      
            }
        }
    

      当然,在这个构造函数里,可以完整的写上完整的连接字符串。

    EF的对象状态

      db.Entry(TEntity).State  (附加Entity,并设置状态)

        public enum EntityState
        {
            // 摘要: 
            //     The entity is not being tracked by the context.  An entity is in this state
            //     immediately after it has been created with the new operator or with one of
            //     the System.Data.Entity.DbSet Create methods.
            Detached = 1,
            //
            // 摘要: 
            //     The entity is being tracked by the context and exists in the database, and
            //     its property values have not changed from the values in the database.
            Unchanged = 2,
            //
            // 摘要: 
            //     The entity is being tracked by the context but does not yet exist in the
            //     database.
            Added = 4,
            //
            // 摘要: 
            //     The entity is being tracked by the context and exists in the database, but
            //     has been marked for deletion from the database the next time SaveChanges
            //     is called.
            Deleted = 8,
            //
            // 摘要: 
            //     The entity is being tracked by the context and exists in the database, and
            //     some or all of its property values have been modified.
            Modified = 16,
        }
    

      

    延迟加载,贪婪加载,为什么需要Virtual

      延迟加载(lazy load)是(也称为懒加载),延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出sql语句进行查询。

      贪婪加载则是一次性把相关的表也加载进来。

    在EF中,默认是支持延迟加载的。

      db.Configuration.LazyLoadingEnabled = false;    //设置禁用延迟加载

    如果想单个贪婪加载某个表。则通过Include("表名")

      db.Orders.Include("OrderItems");          //把OrderItems表一并加载进来

    Virtual关键字

    通常相关连的表作为Entity属性的时候,使用Virtual关键字修饰符。如果不加Virtual关键字,则关联的类只是一个普通的POCO类型。get,set方法为空实现。

    使用Virtual关键字后,EF生成一个代理类来重写get和set方法。实现需要的功能。

      

    绕过EF,直接SQL查询

      EF作为一个框架,也不可能做到满足所有需求。EF提供了直接操作Ado.net方式。

    有三个 API 支持:

    • DbContext.Database.ExecuteSqlCommand
    • DbContext.Database.SqlQuery
    • DbSet.SqlQuery

             

    执行sql 返回受影响函数。

    public int ExecuteSqlCommand(string sql, params object[] parameters); 
    

    执行sql 返回查询结果并自动映射到指定类上。(不会被EF跟踪状态)

    DbRawSqlQuery<TElement> SqlQuery<TElement>(string sql, params object[] parameters);
    

    执行sql 返回查询结果并自动映射到指定类上。(被EF跟踪状态。DbSqlQuery继承自DbRawSqlQuery)

    virtual DbSqlQuery<TEntity> SqlQuery(string sql, params object[] parameters);

    查看EF生成SQL语句

      当使用EF执行一个复杂的查询时候。我们需要知道EF是否按照我们所需执行。这时,就需要查看EF生成的语句。

    1. 执行IQueryable<T>.ToString(); 即可查看生成的sql语句。
    2. 通过EFProviderWrappers,这里不做赘述。

    DataAnnotation

      DataAnnotation 特性由.NET 3.5中引进,给.NET中的类提供了一种添加验证的方式。同时在EF中,也是添加约束与个性化设置一种方式。

    常用到以下特性。

    1. KeyAttribute:对应数据库中的主键
    2. RequiredAttribute:对应数据库中字段的数据是否可以为null
    3. MaxLengthAttribute:对应数据库中字符串类型字段的最大长度
    4. MinLengthAttribute:在数据库中无对应,但在代码中字符串最小长度
    5. TimestampAttribute:将列的数据类型指定为行版本
    6. DatabaseGeneratedAttribute:标记指定实体属性是由数据库生成的,并指定生成策略(None数据库不生成值,Identity当插入行时,数据库生成值,Computed当插入或更新行时,数据库生成值)
    7. ColumnAttribute:指定实体属性在数据库中的列名及数据类型
    8. TableAttribute:指定实体类对应的数据表名
    9. ForeignKeyAttribute:指定导航属性的外键字段
    10. NotMappedAttribute:标记指定实体属性在创建数据库中不创建对应字段
    11. ConcurrencyCheck:并发标记
        public class Order
        {
            [Key]
            public int Id { get; set; }
            [StringLength(200)]
            public string Name { get; set; }
            public int UserId { get; set; }
            [ForeignKey("UserId")]
            public User User { get; set; }
            public virtual ICollection<OrderItem> OrderItems { get; set; }
        }
    

      

    FluentAPI

      使用DataAnnotation(DA)非常方便,但有时我们的POCO类不希望受到EF的直接关联。或者DA不能满足需求。这时,我们可以使用FluentAPI方式。

    1. HasKey - KeyAttribute:配置此实体类型的主键属性
    2. IsRequired - RequiredAttribute:将此属性配置为必需属性。用于存储此属性的数据库列将不可以为null
    3. HasMaxLength - MaxLengthAttribute:将属性配置为具有指定的最大长度
    4. IsConcurrencyToken - ConcurrencyCheckAttribute:将属性配置为用作开放式并发标记
    5. IsRowVersion - TimestampAttribute:将属性配置为数据库中的行版本。实际数据类型将因使用的数据库提供程序而异。将属性设置为行版本会自动将属性配置为开放式并发标记。
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<AppInfo>().Property(o => o.Id).HasColumnName("AppId");
            }
    

      

    MVC异步控制器做个CRUD例子

      微软自家的东西关联总是那么方便。

    在MVC5中,添加控制器的时候选择使用EF即自动生成这一切。

    建议

      1.模型改变重新生成数据库,导致表数据丢失。

        在使用CodeFirst中,当模型改变的时候,采用第一节中的Nuget中EF Migration API方式则不会清空数据。

      2.是否使用存储过程,视图这些数据库技术。

        当使用EF 这种ORM框架的时候,就应该轻数据库技术,重业务逻辑层。我的建议是万不得已不要使用存储过程,视图实际只是存储了SQL语句。

    MVC5代码下载:MVCTest

  • 相关阅读:
    UIAutomation学习入门
    Global.asax详解
    iOS开发之UINavigationController
    iOS开发之控制器创建与加载(生命周期)
    iOS开发之自定义弹出的键盘
    iOS开发之UIWindow
    iOS开发之UIPickerView
    iOS开发之iOS程序的启动过程
    iOS开发之UIApplication和delegate
    iOS开发之UIApplication
  • 原文地址:https://www.cnblogs.com/neverc/p/4668460.html
Copyright © 2011-2022 走看看