Code First:如何实现一个主类中包含多个复类
假设我们在程序中要用到的类的结构是这样的,这里比较特别的是B在A中出现了最少两次
public class B
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class A
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public B B1 { get; set; } /*第一次*/
public B B2 { get; set; } /*第二次*/
}
那我们如何通过EF框架映射到数据库中呢?
如果是下面这种方式就会非常简单,使用
public class B
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class A
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public B B1 { get; set; } /*第一次*/
}
Code First 指定外键名称中的任何方法都可以实现
-------------------------------------------------------------------------------------------
接下来将我使用过程中遇到的错误方法和正确方法都罗列出来
错误方法一:[ForeignKey("F_UserID")]注释 看代码
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApplication1
{
class Program
{ static void Main( string[] args )
{
using (var db = new MyTestContent())
{ db.A.Add(new A
{
Name = "A",
B1 = new B { Name = "B1" },
B2 = new B { Name = "B2" }
}); db.SaveChanges(); A a = db.A.FirstOrDefault();
}
} public class A
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int BId1 { get; set; }
[ForeignKey("BId1")]
public B B1 { get; set; } public int BId2 { get; set; }
[ForeignKey("BId2")]
public B B2 { get; set; }
}
public class B
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
} public class MyTestContent : DbContext
{
public MyTestContent( )
{
Database.SetInitializer<MyTestContent>(null);
}
public DbSet<B> B { get; set; }
public DbSet<A> A { get; set; }
}
}
}
执行add-migratiton createDB生成如下DbMigration
namespace EFLoading.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class createDB : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.A",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
BId1 = c.Int(nullable: false),
BId2 = c.Int(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.B", t => t.BId1, cascadeDelete: true)
.ForeignKey("dbo.B", t => t.BId2, cascadeDelete: true)
.Index(t => t.BId1)
.Index(t => t.BId2); CreateTable(
"dbo.B",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id); } public override void Down()
{
DropForeignKey("dbo.A", "BId2", "dbo.B");
DropForeignKey("dbo.A", "BId1", "dbo.B");
DropIndex("dbo.A", new[] { "BId2" });
DropIndex("dbo.A", new[] { "BId1" });
DropTable("dbo.B");
DropTable("dbo.A");
}
}
}
在程序包管理器控制台中执行:Update-Database –Verbost,会出现这样的错误
Introducing FOREIGN KEY constraint 'FK_dbo.A_dbo.B_BId2' on table 'A' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.

也就是说连数据库都没办法创建成功, 从字面意思上说可能这种方式需要在数据库中取消级联删除和更新功能,然后级联删除和更新需要代码操作来完成。 错误原因:不明确
错误方法二:[Column("BId1")]注释 看代码
按照错误一的方法操作,只是将类A的代码改为下方的样子
public class A
{
[Key]
public int Id { get; set; }
public string Name { get; set; } [Column("BId1")]
public int BId1 { get; set; }
public virtual B B1 { get; set; } [Column("BId2")]
public int BId2 { get; set; }
public virtual B B2 { get; set; }
}

错误方式同方法一:数据库创建失败
正确(可行)的方法:
依赖EF框架自动生成外键, 我们只需要指定导航属性即可,EF自动创建命名规则为:“表名_主键名”的复键
代码奉上
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace EFLoading
{
class Program
{
static void Main(string[] args)
{
using (var ctx = new EFLoadingContext())
{
A InsertA = new A
{
Name = "A",
B1 = new B { Name = "B1" },
B2 = new B { Name = "B2" }
};
ctx.A.Add(InsertA); ctx.SaveChanges(); A readA = ctx.A.FirstOrDefault();
}
}
} public class A
{
[Key]
public int Id { get; set; }
public string Name { get; set; } public virtual B B1 { get; set; } public virtual B B2 { get; set; }
}
public class B
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
} public class EFLoadingContext : DbContext
{
public EFLoadingContext( )
{
Database.SetInitializer<EFLoadingContext>(null);
}
public DbSet<A> A { get; set; }
public DbSet<B> B { get; set; }
}
}
执行add-migration createDB命令后生成的DbMigration的代码
namespace EFLoading.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class createDB : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.A",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
B1_Id = c.Int(),
B2_Id = c.Int(),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.B", t => t.B1_Id)
.ForeignKey("dbo.B", t => t.B2_Id)
.Index(t => t.B1_Id)
.Index(t => t.B2_Id); CreateTable(
"dbo.B",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(),
})
.PrimaryKey(t => t.Id); } public override void Down()
{
DropForeignKey("dbo.A", "B2_Id", "dbo.B");
DropForeignKey("dbo.A", "B1_Id", "dbo.B");
DropIndex("dbo.A", new[] { "B2_Id" });
DropIndex("dbo.A", new[] { "B1_Id" });
DropTable("dbo.B");
DropTable("dbo.A");
}
}
}
执行
Update-Database -Verbose
命令数据库创建成功 数据库结构如下
我们再来看看程序执行后内存中的结果

级联更新成功了
同样方法测试级联删除也成功了
需要特别注意的地方
在A类的构造函数中不能包含B1 B2的new函数,比如下面的就会无法级联更新(更新后值都被清空了) ,下面是错误的 错误的 错误的
public class A
{
public A( )
{
B1 = new B { };
B2 = new B { };
}
[Key]
public int Id { get; set; }
public string Name { get; set; } public virtual B B1 { get; set; } public virtual B B2 { get; set; }
}
Code First:如何实现一个主类中包含多个复类的更多相关文章
- 一个.java源文件中可以有多个类吗?(内部类除外)有什么条件?
一个.java源文件中可以有多个类吗?(内部类除外)有什么条件?带着这个疑惑,动手建几个测试类, 揭开心中的疑惑.以下是解开疑惑过程: package test;/** * 一个.java源文件中可以 ...
- 当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出?
当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出? 问题: orderStatus 和 payStatus都是枚举类,并且枚举的个数达地10来个,我们不可能在模板页面(jsp/ftl ...
- Path,Files巩固,题目:从键盘接收两个文件夹路径,把其中一个文件夹中(包含内容)拷贝到另一个文件夹中
这个题目用传统的File,InputStream可以做,但是如果用Files,Path类做,虽然思路上会困难一些,但是代码简洁了很多,以下是代码: import java.io.IOException ...
- YTU 2618: B 求类中数据成员的最大值-类模板
2618: B 求类中数据成员的最大值-类模板 时间限制: 1 Sec 内存限制: 128 MB 提交: 430 解决: 300 题目描述 声明一个类模板,类模板中有三个相同类型的数据成员,有一函 ...
- 对Integer类中的私有IntegerCache缓存类的一点记录
对Integer类中的私有IntegerCache缓存类的一点记录 // Integer类有内部缓存,存贮着-128 到 127. // 所以,每个使用这些数字的变量都指向同一个缓存数据 // 因此可 ...
- 黑马基础阶段测试题:创建Phone(手机)类,Phone类中包含以下内容:
package com.swift; public class Phone { private String pinpai; private int dianliang; public String ...
- 如何在其他类中实现继承自CFormView类的对象
今天项目开发中,我们创建了一个对话框资源,并创建了一个派生自CFormView的类(假设为CMyClassDlg)来管理它. CMyClassDlg.h #pragma once // CMyClas ...
- 在JBPM的Handle类中调用Spring管理的类
我们在使用JBPM定义流程的时候经常要在流程定义文件中加入一个继承xxxHandler的类来实现我们的业务逻辑判断或者其他的需求,在这个类中一般都是用Spring的Application来获取,而这种 ...
- String类中"=="、equals和普通类中"=="、equals的比较
package cn.method.demo; public class StringDemo2 { public static void main(String[] args) { String s ...
随机推荐
- PHP第四章数组2
$str =array("dd"=>"d","dc"=>"ds","dd"=>&q ...
- Clean Code(二):函数
笔记2:函数1.短小.还要更短小 每个函数都一目了然,每个函数灰依序把你带到下一个函数 if.else.while语句等,其中的代码块应该只有一行,块内调用的函数名称应该较具有说明性2.只 ...
- Java SSL/TLS Socket实现
通信端无需向对方证明自己的身份,则称该端处于"客户模式",否则称其处于"服务器模式",无论是客户端还是服务器端,都可处于"客户模式"或者&q ...
- MySQL数据库分表的3种方法
原文地址:MySQL数据库分表的3种方法作者:dreamboycx 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目 ...
- Web电子商务网(三层)V2.0源码
Web电子商务网(三层)V2.0源码 源码描述: 一.源码特点 采用三层架构开发,购物车功能 二.功能介绍 前台集成了产品在线展示,用户注册.在线调查.在线投稿 后台有类别管理\图书管理\订单 ...
- Opencv读取视频一闪而过情况分析
在参加一个软件比赛需要用opencv对视频的处理,也碰到了一些问题. 最常见的就是视频一闪而过了,在网上查了好久都没解决, 最后重装在配置环境变量时发现的. 现在我来终结一下估计是比较全的了. 先说明 ...
- Android开发MVP模式解析
http://www.cnblogs.com/bravestarrhu/archive/2012/05/02/2479461.html 在开发Android应用时,相信很多同学遇到和我一样的情况,虽然 ...
- javascript GB2312转UTF8
/* * GB2312转UTF8 * 例: * var xx=new GB2312UTF8(); * var Utf8=xx.Gb2312ToUtf8("你aaa好aaaaa"); ...
- 记一次ios使用OAuth 2.0写的接口获取token的小错
1.用ios原生网络请求的话,请求参数不能这样传 而要这样传 2.用afnetworking的话,要注意各个参数有没有错误,参数可以直接这样传
- C#一些小技巧
在C#实现类似Typedef的所有功能 Typedef这个关键字,是比较好用的东西,因为有时候我们需要使用一些别名来帮助我们记忆某些结构体或者类的共用.(个人觉得这是C与C++唯一能吸引我的东西)为了 ...