Entity Framework使用建模之Code First 一对多

使用这种方式请首先安装EntityFramework4.1.exe,您可以去这里下载:

ADO.NETEntity Framework 4.1

Code First是EF建模的第三种方式,也是最灵活的一种方式,这种方式需要自己手动编写代码实现实体对象、对象关系,并提供注解映射信息,这种方式的本质是将基于图形界面的Model First设计方式改为基于手动编写代码的方式,这并不意味着code就效率低下,通过代码生成工具支持,开发效率一样很高。

一对多的示例

一个游戏账号可以创建多个游戏角色

/// <summary> /// 游戏账号 /// 通过Data Annotations实现实体到数据库结构的映射 /// </summary> [Table("GameUsers")] public class GameUser { [Key] //[Column("GAME_USER_ID")] [MaxLength(8)] [DatabaseGenerated(DatabaseGeneratedOption.None)] public string GameUserID { get; set; } [Column("GAME_USER_NAME")] [Required] [MaxLength(32)] public string GameUserName { get; set; } [Column("GAME_USER_PASSWORD")] [MaxLength(16)] public string GameUserPassword { get; set; } public DateTime GameUserTime { get; set; } /// <summary> /// 该属性不被映射 /// </summary> [NotMapped] public string Comment { get; set; } [ConcurrencyCheck] [Timestamp] public byte[] TimeStamp { get; set; } /// <summary> /// 游戏账户档案 /// </summary> public GameUserArchive GameUserArchive { get; set; } public virtual ICollection<GameRole> GameRoles { get; set; } } [Key] //[Column("GAME_USER_ID")] [MaxLength(8)] [DatabaseGenerated(DatabaseGeneratedOption.None)] public string GameUserID { get; set; } [Column("GAME_USER_NAME")] [Required] [MaxLength(32)] public string GameUserName { get; set; } [Column("GAME_USER_PASSWORD")] [MaxLength(16)] public string GameUserPassword { get; set; } [MaxLength(16)] public DateTime GameUserTime { get; set; } /// <summary> /// 该属性不被映射 /// </summary> [NotMapped] public string Comment { get; set; } [ConcurrencyCheck] [Timestamp] public byte[] TimeStamp { get; set; } /// <summary> /// 游戏账户档案 /// </summary> public GameUserArchive GameUserArchive { get; set; } public virtual ICollection<GameRole> GameRoles { get; set; } }
/// <summary> /// 账号角色 /// 通过Data Annotations实现实体到数据库结构的映射 /// </summary> [Table("GameRoles")] public class GameRole { [Key] //[Column("GameRoleID")] //[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)] public int GameRoleID { get; set; } /// <summary> /// 所属账户编号 /// </summary> [Required] [MaxLength(8)] public string GameUserID { get; set; } /// <summary> /// 角色名 /// </summary> //[Required] //[MaxLength(32)] public string GameRoleName { get; set; } /// <summary> /// 所属账户对象 /// </summary> [ForeignKey("GameUserID")] [InverseProperty("GameRoles")] public virtual GameUser GameUser { get; set; } }

/// <summary> /// 游戏用户档案 /// 通过Data Annotations实现实体到数据库结构的映射 /// </summary> [ComplexType] public class GameUserArchive { /// <summary> /// 身份证 /// </summary [Required] [MaxLength(18)] public string IdentityCard { get; set; } [MaxLength(64)] public string HomeAddress { get; set; } [MaxLength(16)] public string ContactPhone { get; set; } }

说明:

实体到数据库结构的映射是通过默认的约定来进行的,如果需要修改的话,有两种方式,分别是:Data Annotations 和 Fluent API,本例使用的是Data Annotations 来修改实体到数据库结构的映射

以上类的编写中,我们用了很多C#的Attribute[特性]:

       Table:指定实体所对应的数据库的表名,不指定则对应的表名为类名的复数形式 

       Key:指定是否是主键,不指定则 Code First 会将名为“Id”或“<类名>Id”的字段推断为主键,且如果它的类型是"int"或"long"或"short"的话,则会在数据库中默认注册为 identity 字段。注:主键的推断与大小写无关 

DatabaseGenerated:指定字段的值在数据库中的生成方式

DatabaseGeneratedOption.None :不做任何处理

 

             DatabaseGeneratedOption.Identity:标识列

DatabaseGeneratedOption.Compute:计算列

              Required:指定为必填字段,即指定数据库对应的列不允许为 null 值

              MaxLength:指定字段的最大长度,未指定则为 max

              StringLength:指定字段的长度范围

              Column:指定字段所对应的数据库中的列名,默认情况下数据库中的列名同 Code First 中的字段名

              NotMapped:没有对应关系,即此字段不会在数据库中生成对应的列

              Timestam:指定对应的数据库中的列的类型为DateTime

              ForeignKey:指定外键的名称,默认情况下与导航属性的主键名称相同的字段会自动被标记为外键

              InverseProperty :指定导航属性的反转属性,默认情况下按实体的互相引用自行推断  

ComplexType :复杂类型,如果字段类型为一个实体类,则此字段会被自动标记为复杂类型,被标记为复杂类型的字段为必填字段,复杂类型的每个属性将作为所属类型的表的字段存在。

              Timestamp :将 Code First 中的类型为 byte[] 的字段对应到数据库中的类型为 timestamp 的列

              ConcurrencyCheck:指定字段为用于乐观并发检查的字段,为了简单,建议同时将此字段也标记为Timestamp

 

CodeFirstDbContext实现:


/// <summary> /// 自定义类必须继承自DbContext,DbContext来自EF4.1的EntiyFramework.dll这个程序集 /// </summary> public class CodeFirstDbContext:DbContext { public DbSet<GameUser> GameUsers { get; set; } public DbSet<GameRole> GameRoles { get; set; } public CodeFirstDbContext() { } public CodeFirstDbContext(string conn):base(conn) { //是否启用延迟加载: // true: 延迟加载(Lazy Loading):获取实体时不会加载其导航属性,一旦用到导航属性就会自动加载 // false: 直接加载(Eager loading):通过 Include 之类的方法显示加载导航属性,获取实体时会即时加载通过 Include 指定的导航属性 this.Configuration.LazyLoadingEnabled = true; this.Configuration.AutoDetectChangesEnabled = true; //自动监测变化,默认值为 true } /// <summary> /// 实体到数据库结构的映射是通过默认的约定来进行的,如果需要修改的话,有两种方式,分别是:Data Annotations 和 Fluent API // 以下示范通过 Fluent API 来修改实体到数据库结构的映射 /// </summary> /// <param name="modelBuilder"></param> protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<GameRole>() .Property(p => p.GameRoleID) .HasColumnName("GameRoleID")//设置映射的表字段名 .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)//设置映射字段的值生成方式为标识列 .IsRequired();//设置字段值是必须的 modelBuilder.Entity<GameRole>() .Property(p => p.GameRoleName) .HasMaxLength(32)//字段长度 .IsOptional()//字段的值可以为空 .IsUnicode()//字段值类型为nvarchar .IsVariableLength();//字段长度是可变的 base.OnModelCreating(modelBuilder); } }

使用示范:

/// <summary> /// 创建数据库 /// </summary> static void Demo4() { using (CodeFirstDbContext db = new CodeFirstDbContext()) { if (db.Database.Exists()) { Console.WriteLine("数据库已经存在,您是否删除数据库重新创建(yes/no)?"); if (Console.ReadLine().ToLower() == "yes") { Console.WriteLine("准备删除数据库"); db.Database.Delete(); Console.WriteLine("准备创建数据库"); db.Database.Create(); } } } } /// <summary> /// 添加数据 /// </summary> static void Demo5() { using (EFLabCodeFirst.CodeFirstDbContext db = new CodeFirstDbContext()) { db.GameUsers.Add(new GameUser { GameUserID = "GU0001", GameUserName = "飞影", GameUserPassword = "123", GameUserTime = DateTime.Now, GameUserArchive = new GameUserArchive { IdentityCard = "123123123123123123", HomeAddress = "兰台路", ContactPhone = "111" } }); db.GameUsers.Add(new GameUser { GameUserID = "GU0002", GameUserName = "藏龙", GameUserPassword = "112", GameUserTime = DateTime.Now, GameUserArchive = new GameUserArchive { IdentityCard = "112233221122332211", HomeAddress = "科华路", ContactPhone = "222" } }); GameUser user3 = new GameUser { GameUserID = "GU0003", GameUserName = "卧虎", GameUserPassword = "212", GameUserTime = DateTime.Now, GameUserArchive = new GameUserArchive { IdentityCard = "111222333444444444", HomeAddress = "仙桥路", ContactPhone = "333" } }; db.GameUsers.Add(user3); db.GameRoles.Add(new GameRole { GameRoleName = "火影", GameUserID = "GU0001" });//采用GameUserID关联一个账户ID db.GameRoles.Add(new GameRole { GameRoleName = "飞天", GameUserID = "GU0001" });//采用GameUserID关联一个账户ID db.GameRoles.Add(new GameRole { GameRoleName = "小刀", GameUserID = "GU0002" });//采用GameUserID关联一个账户ID db.GameRoles.Add(new GameRole { GameRoleName = "飞虎", GameUserID = "GU0003" });//采用GameUserID关联一个账户ID db.SaveChanges(); } } /// <summary> /// 查询所有账户和角色 /// </summary> static void Demo6() { using (CodeFirstDbContext db = new CodeFirstDbContext()) { db.GameUsers.Include("GameRoles").AsEnumerable()//Include:预加载关联的对象 .Select(u => { Console.WriteLine(u.GameUserID+"\t"+u.GameUserName); u.GameRoles.AsEnumerable().Select(r => { Console.WriteLine("\t"+r.GameRoleID+"\t"+r.GameRoleName); return r; }).Count(); return u; }).Count(); } } //以下内容摘自别人博客,时间紧张这里不再示范: /* DbContext API常用方法 db.GameUsers.Find() - 通过传递主键值作为参数查找实体,复合主键就传多个参数 db.GameUsers.Add() - 把一个新增的实体添加到上下文 db.GameUsers.Attach() - 把一个已存在的实体添加到上下文 db.Entry(entity).State = System.Data.EntityState.Modified - 修改实体状态 db.GameUsers.AsNoTracking() - 不被 Context 跟踪,通过 NoTracking 获取的实体,其状态是 Detached 状态。当仅仅是获取数据的时候可以用,有助于提高效率 属性的相关操作,当属性改变时,会自动监测实体状态,即 IsModified = true db.Entry(GameUser).Property(p => p.GameUserName).CurrentValue db.Entry(GameUser).Property("GameUserName").CurrentValue 直接加载(Eager loading)的方法 db.GameUsers.Include(p => p.GameRoles.First()) db.GameUsers.Include(p => p.GameRoles) db.Entry(GameRole).Reference(p => p.GameUser).Load() 使用 sql db.GameUsers.SqlQuery("select * from GameUsers").ToList() // 有实体的情况 db.Database.SqlQuery<string>("select GameUserName from GameUsers").ToList(); // 无实体的情况 db.Database.ExecuteSqlCommand(commandText); // 直接执行 sql */

 

生成的表结构如下:




转载于:https://www.cnblogs.com/Ruiky/archive/2012/06/27/2565647.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值