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. Redis客户端开发包:Jedis学习-入门

    添加Jedis依赖 我们可以使用以下三种方式来添加Jedis依赖. 1.下载jar文件 从http://search.maven.org/下载最近的jedis包和Apache Commons Pool ...

  2. Asp.net MVC的Model Binder工作流程以及扩展方法(2) - Binder Attribute

    上篇文章中分析了Custom Binder的弊端: 由于Custom Binder是和具体的类型相关,比如指定类型A由我们的Custom Binder解析,那么导致系统运行中的所有Action的访问参 ...

  3. List 简单升\降序实现

    public class User { public int Id { get; set; } public string Code { get; set; } } //示例 //升序 list.So ...

  4. ibatis动态多条件查询及模糊查询(oracle,mysql,sql)

    首先是模糊查询的问题,开始时我使用如下条件:select * from user where name like '%#value#%'. 可是怎么也不行,好像还报错了.后来在网上找到了解决方法,就是 ...

  5. my_log

    //功能:定时向文件中写入时间,如果进程终止,下次打开同一个文件会继续之前的编号书写 #include<stdio.h> #include<time.h> int main(i ...

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

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

  7. 第10章 同步设备I/O和异步设备I/O(3)_接收I/O请求完成通知的4种方法

    10.5 接收I/O请求完成的通知 (1)I/O请求被加入设备驱动程序的队列,当请求完成以后,设备驱动也要负责通知我们I/O请求己经完成. (2)可以用4种方法来接收I/O请求己经完成的通知 技术 特 ...

  8. Windows 常用 CMD 命令行介绍

    看下面的链接: http://www.jianshu.com/p/76ff5d16f113

  9. 完全平方数(钟神的hao)

    [问题描述] 从1− ?中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少. [输入格式] 第一行一个数字?. [输出格式] 一行一个整数代表答案对100000007取模之后的答 ...

  10. javascript获取元素的方法[xyyit]

    1. javascript默认的方法: <div id=”div_id” class=”div_class” name=”div_name”></div> //1. 根据id ...