• 精进不休 .NET 4.0 (9) ADO.NET Entity Framework 4.1 之 Code First


    [索引页]
    [源码下载] 


    精进不休 .NET 4.0 (9) - ADO.NET Entity Framework 4.1 之 Code First



    作者:webabcd


    介绍
    ADO.NET Entity Framework 4.1 的新增功能:Code First


    示例
    Web.config

    <?xml version="1.0"?>
    <configuration>
        <connectionStrings>
            <!--
                需要将 Persist Security Info 设置为 True,以便保存密码信息
                因为 Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>()); 在判断 Code First 与数据库结构是否一致时需要连接 master 库
            -->
            <add name="MyConnection" providerName="System.Data.SqlClient" connectionString="server=.;database=MyDB;uid=sa;pwd=111111;Persist Security Info=True" />
        </connectionStrings>
    </configuration>

    Global.asax.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.SessionState;
    
    using System.Data.Entity;
    using EF41.CodeFirst;
    
    namespace EF41
    {
        public class Global : System.Web.HttpApplication
        {
            protected void Application_Start(object sender, EventArgs e)
            {
                // 当 Code First 与数据库结构不一致时,删除原数据库,根据 Code First 重新生成新的数据库结构
                Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
    
                // 什么都不做
                // Database.SetInitializer<MyContext>(null);
            }
        }
    }

    Category.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace EF41.CodeFirst
    {
        public class Category
        {
            public string CategoryId { get; set; }
            public string Name { get; set; }
            public string Comment { get; set; }
    
            public virtual ICollection<Product> Products { get; set; }
        }
    }

    Product.cs

    /*
     * 实体到数据库结构的映射是通过默认的约定来进行的,如果需要修改的话,有两种方式,分别是:Data Annotations 和 Fluent API
     * 以下介绍通过 Data Annotations 来修改实体到数据库结构的映射(通过 Fluent API 来修改实体到数据库结构的映射的方法参见 MyContext.cs 文件)
     *     Table - 指定实体所对应的数据库的表名,不指定则对应的表名为类名的复数形式
     *     Key - 指定是否是主键,不指定则 Code First 会将名为“Id”或“<类名>Id”的字段推断为主键,且如果它的类型是"int"或"long"或"short"的话,则会在数据库中默认注册为 identity 字段。注:主键的推断与大小写无关
     *     DatabaseGenerated - 指定字段的值在数据库中的生成方式
     *         DatabaseGeneratedOption.None - 不做任何处理
     *         DatabaseGeneratedOption.Identity - 标识列
     *         DatabaseGeneratedOption.Computed - 计算列
     *     Required - 指定为必填字段,即指定数据库对应的列不允许为 null 值
     *     MaxLength - 指定字段的最大长度,未指定则为 max
     *     StringLength - 指定字段的长度范围
     *     Column - 指定字段所对应的数据库中的列名,默认情况下数据库中的列名同 Code First 中的字段名
     *     NotMapped - 没有对应关系,即此字段不会在数据库中生成对应的列
     *     Timestamp - 指定对应的数据库中的列的类型为 datetime
     *     ForeignKey - 指定外键的名称,默认情况下与导航属性的主键名称相同的字段会自动被标记为外键
     *     InverseProperty - 指定导航属性的反转属性,默认情况下按实体的互相引用自行推断
     *         所谓“反转属性”,按本例看就是 Product.Category 的反转就是 Category.Products
     *     ComplexType - 复杂类型,如果字段类型为一个实体类,则此字段会被自动标记为复杂类型,被标记为复杂类型的字段为必填字段,参见 Price.cs 文件
     *     Timestamp - 将 Code First 中的类型为 byte[] 的字段对应到数据库中的类型为 timestamp 的列
     *     ConcurrencyCheck - 指定字段为用于乐观并发检查的字段,为了简单,建议同时将此字段也标记为 Timestamp
     */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    using System.ComponentModel.DataAnnotations;
    
    namespace EF41.CodeFirst
    {
        [Table("CategoryProduct")]
        public class Product
        {
            [Key]
            [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
            public int ProductId { get; set; }
    
            [Required]
            [MaxLength(128)] // [StringLength(128, MinimumLength = 16)]
            [Column("ProductName")]
            public string Name { get; set; }
    
            [NotMapped]
            public string Comment { get; set; }
    
            public DateTime CreateTime { get; set; }
    
            public Price Price { get; set; }
    
            [ConcurrencyCheck]
            [Timestamp]
            public byte[] TimeStamp { get; set; } 
    
            public string CategoryId { get; set; }
    
            [ForeignKey("CategoryId")]
            [InverseProperty("Products")]
            public virtual Category Category { get; set; }
        }
    }

    Price.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    using System.ComponentModel.DataAnnotations;
    
    namespace EF41.CodeFirst
    {
        // 以本例来说,对应到数据库的列将被拆为两个,分别是:Price_Dollar 和 Price_RMB,且均为必填列
        [ComplexType]
        public class Price
        {
            public Price()
            {
                Dollar = null;
                RMB = null;
            }
    
            public decimal? Dollar { get; set; }
            public decimal? RMB { get; set; }
        }
    }

    MyContext.cs

    /*
     * 需要引用 EntityFramework(版本 4.1)
     * 需要引用 System.Data.Entity
     * 需要引用 System.ComponentModel.DataAnnotations
     */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    using System.Data.Entity;
    
    namespace EF41.CodeFirst
    {
        // 创建的 Context 要继承自 DbContext
        public class MyContext : DbContext
        {
            // 构造函数中的参数用于指定 connectionStrings 的 name
            // 默认值为 Context 类的类全名,本例为 EF41.CodeFirst.MyContext
            public MyContext(string connString)
                : base(connString)
            {
                // DbContextConfiguration.LazyLoadingEnabled - 是否启用延迟加载,默认值为 true
                //     true - 延迟加载(Lazy Loading):获取实体时不会加载其导航属性,一旦用到导航属性就会自动加载
                //     false - 直接加载(Eager loading):通过 Include 之类的方法显示加载导航属性,获取实体时会即时加载通过 Include 指定的导航属性
                this.Configuration.LazyLoadingEnabled = true;
    
                // DbContextConfiguration.AutoDetectChangesEnabled - 是否自动监测变化,默认值为 true
                this.Configuration.AutoDetectChangesEnabled = true;
            }
    
            // 所有需要关联到 Context 的类都要类似如下代码这样定义
            public DbSet<Category> Categories { get; set; }
            public DbSet<Product> Products { get; set; }
    
            // 实体到数据库结构的映射是通过默认的约定来进行的,如果需要修改的话,有两种方式,分别是:Data Annotations 和 Fluent API
            // 以下介绍通过 Fluent API 来修改实体到数据库结构的映射(通过 Data Annotations 来修改实体到数据库结构的映射的方法参见 Product.cs 文件)
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Category>()
                    .Property(s => s.Name)
                    .IsUnicode(false) // 指定对应到数据库的类型为 varchar,IsUnicode(true) 为 nvarchar,默认为 nvarchar
                    .IsRequired() // 指定对应到数据库的列为必填列
                    .HasMaxLength(64); // 指定对应到数据库的列的最大长度为 64
            }
        }
    }

    Demo.aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    using System.Data.Entity;
    
    namespace EF41.CodeFirst
    {
        public partial class Demo : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                // Code First 中通过 DbContext API 实现增删改查的 Demo
                using (var db = new MyContext("MyConnection"))
                {
                    Random random = new Random();
    
                    var category = new Category { CategoryId = Guid.NewGuid().ToString(), Name = "software " + random.Next(1, int.MaxValue) };
                    db.Categories.Add(category);
    
                    var product = new Product { Name = "windows " + random.Next(1, int.MaxValue), Category = category, CreateTime = DateTime.Now, Price = new Price() };
                    var product2 = new Product { Name = "windows " + random.Next(1, int.MaxValue), Category = category, CreateTime = DateTime.Now, Price = new Price() };
                    db.Products.Add(product);
                    db.Products.Add(product2);
    
                    int recordsAffected = db.SaveChanges();
                    Response.Write("影响到数据库的行数:" + recordsAffected.ToString());
    
    
                    /*
                     * DbContext API 的一些关键点
                     * 
                     * db.Categories.Find() - 通过传递主键值作为参数查找实体,复合主键就传多个参数
                     * db.Categories.Add() - 把一个新增的实体添加到上下文
                     * db.Categories.Attach() - 把一个已存在的实体添加到上下文
                     * db.Entry(entity).State = System.Data.EntityState.Modified - 修改实体状态
                     * db.Categories.AsNoTracking() - 不被 Context 跟踪,通过 NoTracking 获取的实体,其状态是 Detached 状态。当仅仅是获取数据的时候可以用,有助于提高效率
                     * 属性的相关操作,当属性改变时,会自动监测实体状态,即 IsModified = true
                     *     db.Entry(product).Property(p => p.Name).CurrentValue
                     *     db.Entry(product).Property("Name").CurrentValue
                     * 直接加载(Eager loading)的方法
                     *     db.Categories.Include(p => p.Products.First())
                     *     db.Categories.Include(p => p.Products)
                     *     db.Entry(product).Reference(p => p.Category).Load()
                     * 使用 sql
                     *     db.Categories.SqlQuery("select * from Categories").ToList() // 有实体的情况
                     *     db.Database.SqlQuery<string>("select Name from Categories").ToList(); // 无实体的情况
                     *     db.Database.ExecuteSqlCommand(sql); // 直接执行 sql
                     */
                }
            }
        }
    }


    OK 
    [源码下载]

  • 相关阅读:
    javascript变量作用域、匿名函数及闭包
    SenchaTouch2中navigation下嵌入list无事件响应问题解决
    Fedora17安装SSH
    25个必须记住的SSH命令
    linux下安装hadoop
    Fedora17实现图形界面root登录
    virtualBox利用已创建的vdi文件克隆快速创建新虚拟机
    printf/scanf格式修饰符
    windowsServer2003服务器上修改ftp端口号
    为ckeditor添加行距的功能(转载)
  • 原文地址:https://www.cnblogs.com/webabcd/p/2054002.html
Copyright © 2020-2023  润新知