Entity Framework Code First 简称 EF CF也行,就是在开发的时候,以代码先行的原则,开发人员无需考虑

数据库端的一些问题(开发过程中基本不需要在数据库管理器上操作)

言归正传吧,最近刚刚入手MVC EF 的CF开发,原因就是他的开发效率比较高,适合中小型项目。既然说到项目,那就涉及到稍微复杂点的数据表关系。要使用联合查询,外键等技术才能实现一些功能。

下面举例说明我在实际测试中遇到的一些问题。

场景:用户权限管理系统中的关系——分为 公司 部门 职员 3个表

由于是用CF形式开发,所以我直接在model层写下3个模型,以阐述3个表的关系。

本测试经过3次测试

第一次测试:标准的约定配置,主从表均加入描述:

========================================================
如主表加导航属性 public virtual ICollection<。。。>

从表加引入属性             public int 外键{ get; set; } <-----此处制定外键
                [ForeignKey("外键")]
                  public virtual 引用实体 实体{ get; set; }

代码如下!

WorkGroup

公司表,每个公司有N个角色(总经理,财务部,开发部等)

namespace MvcDemo.Model.System
{
public class WorkGroup
{
[Key]
//公司的唯一ID
public int ID { get; set; }
//公司下可能有子公司所以此表可以作为递归表
public int PID { get; set; }
//公司的名称
public string GroupName { get; set; }
//公司的描述
public string Description { get; set; }
//公司是否通过管理员的验证(本系统可以负责多个公司的人员管理,系统管理员需要审批是否允许某公司使用本系统)
public bool IsPassed { get; set; }
//一个公司下有多个职员
public virtual ICollection<UserBase> UserBase { get; set; }
//一个公司下有多个权限
public virtual ICollection<UserGroup> UserGroup { get; set; }
}
}

UserGroup

职务角色表,每个职务角色都隶属于某个公司,每个职务下面都有N个职员一起共事

namespace MvcDemo.Model.User
{
public class UserGroup
{
[Key]
//职务角色表的唯一ID
public int ID { get; set; }
[Required]
//职务下面可能也有子角色,本表也可以使用递归表,描述更复杂的关系,一般可以不用
public int PID { get; set; }
//该职务的状态,公司的管理者通过控制角色状态来打开或者关闭当前角色的操作权限
public int Status { get; set; }
[Required,MinLength(),MaxLength()]
//职务权限名称
public string GroupName { get; set; }
//权限隶属于某个公司
public int WorkGroupID { get; set; }
[ForeignKey("WorkGroupID")]
public virtual WorkGroup WorkGroup { get; set; }
//一个权限下有多个职员
public virtual ICollection<UserBase> UserBase { get; set; }
}
}

UserBase
职员表,每个职员比如隶属于某个公司,当然他在某个公司下要拥有属于自己的角色,所以他也隶属于某个公司某个职务

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using MvcDemo.Model.System; namespace MvcDemo.Model.User
{
public class UserBase
{
[Key]
//职员的唯一ID
public int ID { get; set; }
[Required]
[StringLength(, MinimumLength = , ErrorMessage = "*")]
//登录名
public string LoginName { get; set; }
[Required]
[StringLength(, MinimumLength = , ErrorMessage = "*")]
//密码
public string LoginPass { get; set; }
//状态,他是否通过本公司的验证
public int Status { get; set; } //一个用户隶属于某个公司
public int WorkGroupID { get; set; }
[ForeignKey("WorkGroupID")]
public virtual WorkGroup WorkGroup { get; set; } //一个职员隶属于某个权限
public int UserGroupID { get; set; }
[ForeignKey("UserGroupID")]
public virtual UserGroup UserGroup { get; set; }
}
}

编写数据上下文类,这样就会自动生成数据库了

    public class DbContextBase : DbContext
{
public DbSet<UserBase> UserBase { get; set; }
public DbSet<UserGroup> UserGroup { get; set; }
public DbSet<WorkGroup> WorkGroup { get; set; }
//public DbSet<AdminBase> AdminBase { get; set; }
//public DbSet<SysMenu> SysMenu { get;set;}
//public DbSet<SysOperation> SysOperation { get; set; } public DbContextBase()
: base("DBConn")
{
Database.CreateIfNotExists();
//此处是自动更新数据表,当模型改变的时候。如果需要加测试数据,用下面的DBInitializer,并在Global
//加入Database.SetInitializer<MvcDemo.DAL.DbContextBase>(new MvcDemo.DAL.DBInitializer()); //修改Model后,自动更新数据表
Database.SetInitializer<DbContextBase>(new DropCreateDatabaseIfModelChanges<DbContextBase>());
//this.Configuration.LazyLoadingEnabled = true; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();//移除复数表名的契约
}
}

此处附webconfig的链接字符串,本例直接用MS SQL,这样可以方便以后测试的时候观测具体执行的SQL语句是否是我们想要的!sql profiler

  <connectionStrings>
<add name="DBConn" connectionString="Data Source=(local);Initial Catalog=MvcDemoData;Persist Security Info=True;User ID=sa;Password=tommyheng" providerName="System.Data.SqlClient" />
</connectionStrings>

此时我们DEBUG,提示出错:

“/”应用程序中的服务器错误。


将 FOREIGN KEY 约束 'FK_dbo.UserGroup_dbo.WorkGroup_WorkGroupID' 引入表 'UserGroup' 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
无法创建约束。请参阅前面的错误消息。

说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。

异常详细信息: System.Data.SqlClient.SqlException: 将 FOREIGN KEY 约束 'FK_dbo.UserGroup_dbo.WorkGroup_WorkGroupID' 引入表 'UserGroup' 可能会导致循环或多重级联路径。请指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
无法创建约束。请参阅前面的错误消息。

源错误:

行 24:         public T Add(T entity)
行 25: {
行 26: context.Set<T>().Add(entity);
行 27: context.SaveChanges();
行 28: return entity;

源文件: f:\MVCWEB\MvcDemo.Web\MvcDemo.DAL\BaseRepository.cs    行: 26

第二次测试:标准的约定配置,主从表均加入描述,但不加自定义的外键:

========================================================

如主表加导航属性 public virtual ICollection<。。。>

从表加引入属性       public virtual 引用实体 实体{ get; set; }

注意:::这里木有任何自定义的外键,也就是说,我们让系统给我们自动生成外键,而不再自己指定外键!

代码如下!

WorkGroup

原样不变!!!!

UserGroup

职务角色表,每个职务角色都隶属于某个公司,每个职务下面都有N个职员一起共事
{为了简化篇幅,我们仅仅把需要修改的地方贴出来。注释掉下面几行,也就是去掉手写的外键}

//权限隶属于某个公司
//public int WorkGroupID { get; set; }
//[ForeignKey("WorkGroupID")]

UserBase
{注释掉下面几行,也就是去掉手写的外键}
职员表,每个职员比如隶属于某个公司,当然他在某个公司下要拥有属于自己的角色,所以他也隶属于某个公司某个职务

//一个用户隶属于某个公司
//public int WorkGroupID { get; set; }
//[ForeignKey("WorkGroupID")]
public virtual WorkGroup WorkGroup { get; set; } //一个职员隶属于某个权限
//public int UserGroupID { get; set; }
//[ForeignKey("UserGroupID")]
public virtual UserGroup UserGroup { get; set; }

完毕!!!

DEBUG测试!成功!说明罪魁祸首就是自己手动写的这个外键了!

附图:数据库表结构图!

第三次测试:非标准的约定配置,主或从表均加入描述,即,要么在主表加导航属性virtual ICollection,要么在从表加引用属性virtual 引用实体 实体:

========================================================

如主表加导航属性 public virtual ICollection<。。。>

或者

从表加引入属性       public virtual 引用实体 实体{ get; set; }

注意:::这里木有任何自定义的外键,也就是说,我们让系统给我们自动生成外键,而不再自己指定外键!

这里就不附代码了!测试结果,均通过!至于为啥自己加外键不行…… 我没继续研究。呵呵,有懂的,就告诉下吧!实现功能就好了!

在使用EF Code First开发时,遇到的“关系”问题,以及解决方法的更多相关文章

  1. 关于Angular2与蚂蚁的NG-ZOORO一同开发时[disabled]="true"动态绑定失效的解决方法

    在使用Angular2与蚂蚁的NG-ZOORO一同开发时,当我们的表单使用的是formControlName="value"时[disabled]="true" ...

  2. 利用SSH框架开发时遇到的各种Bug及解决方法

    .hibernate自动生成的配置文件 hibernate.cfg.xml 有时候是有问题的,会出现 org.hibernate.HibernateException: Could not parse ...

  3. Brophp框架开发时连接数据库读取UTF8乱码的解决(转)

    Brophp框架开发时连接数据库读取UTF8乱码的解决办法 (2012-09-15 10:41:22) 转载▼ 标签: 杂谈 it php 分类: 建站技术 Brophp框架开发时连接数据库读取UTF ...

  4. 记一次SpringBoot 开发中所遇到的坑和解决方法

    记一次SpringBoot 开发中所遇到的坑和解决方法 mybatis返回Integer为0,自动转型出现空指针异常 当我们使用Integer去接受数据库中表的数据,如果返回的数据中为0,那么Inte ...

  5. 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结

    史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...

  6. 安装CentOS、Linux系统时,GPT分区不能引导的解决方法

    安装系统:CentOS 5.9_64bit时,分区后, 提示如下错误. 解决方法: 1.按ctrl+alt+F2 进入命令行 2.先查看分区 sh #fdisk -l    以下假设分区是/dev/s ...

  7. 百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法

    百度编辑器ueditor 异步加载时,初始化没办法赋值bug解决方法 金刚 前端 ueditor 初始化 因项目中使用了百度编辑器——ueditor.整体来说性能还不错. 发现问题 我在做一个编辑页面 ...

  8. Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法

    Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法 2014-03-27 11:44:46|  分类: Easy UI|举报|字号 订阅     可以使用$.parser.pa ...

  9. 加载驱动模块时Device or resource busy的解决方法

    加载驱动模块时Device or resource busy的解决方法 加载驱动模块时Device or resource busy的解决方法 insmod或modprobe驱动模块时Device o ...

随机推荐

  1. json对象转为字符串,当做参数传递时加密解密

    [son对象  字符串 互相转行] 比如我有两个变量,我要将a转换成字符串,将b转换成JSON对象: var a={"name":"tom","sex ...

  2. 服务器磁盘扩展卷时遭遇“There is not enough space available on the disk(s) to complete this operation.”错误

    在ESX VM的一台服务器由于磁盘空间告警,打算决定给E盘扩展空间,增加20G的空间,在操作过程遭遇了Expanding Disk Volume gives error "There is ...

  3. cacti监控mysql

    cacti监控mysql 2013-09-25 16:21:43 分类: LINUX 原文地址:cacti监控mysql 作者:baochenggood cacti监控mysql 1 下载cacti监 ...

  4. Hello, AnnsShadow!

    Hello! 发现这个神奇的园子快一年了,自己的学习历程磕磕碰碰也过了一年了,想想,这么久了,是时候做些记录做个分享者了. 从一开始的只敢看Blog,到现在自己发表一下自己的所感所想,算是一种成长了吧 ...

  5. python基础(四)运算

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Python的运算符和其他语言类似 (我们暂时只了解这些运算符的基本用法,方便我们 ...

  6. 烂泥:rsync配置文件详解

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 对于rsync服务器来说,最重要和复杂的就是它的配置了.rsync服务器的配置文件为/etc/rsyncd.conf,其控制认证.访问.日志记录等等. ...

  7. https协议了解,以及相关协议的解析

    HTTPS简介 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版. ...

  8. 必须知道的八大种排序算法【java实现】(二) 选择排序,插入排序,希尔算法【详解】

    一.选择排序 1.基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换:然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止. 2.实例 3.算法 ...

  9. 深入理解TCP(一)

    TCP是面向连接的传输层层协议,可以为应用层提供可靠的数据传输服务.所谓的面向连接并不是真正意思上的连接,只不过是在发送数据之前,首先得相互握手,也就是说接收方知道你要发数据给它了.而UDP是面向无连 ...

  10. TCMalloc:线程缓冲的Malloc

    这段时间比较闲,研究下内存管理,从官方文档开始啃起<TCMalloc : Thread-Caching Malloc>. 1.动机 TCMalloc要比glibc 2.3的malloc(可 ...