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 ...
随机推荐
- Java并发——同步容器与并发容器
同步容器类 早期版本的JDK提供的同步容器类为Vector和Hashtable,JDK1.2 提供了Collections.synchronizedXxx等工程方法,将普通的容器继续包装.对每个共有方 ...
- String类概述
(1)多个字符组成的一串数据. 其实它可以和字符数组进行相互转换. (2)构造方法: A:public String() B:public String ...
- 20151225jquery学习笔记---编辑器插件
编辑器(Editor),一般用于类似于 word 一样的文本编辑器,只不过是编辑为 HTML格式的.分类纯 JS 类型的,还有 jQuery 插件类型的.一. 编辑器简介我们使用的 jQuery 版本 ...
- C# 自定义排序
/// <summary> /// 实体 /// </summary> public class Product { public int ID { get; set; } p ...
- IP-MAC绑定导致网络故障
前段时间将一台服务器A的服务迁移至了另外一台服务器B,外网IP地址也顺带迁移过来了,结果网络出现了问题. 其中内网是畅通的,但是外网IP怎么都连不上另外一台路由C(B和C是在一个交换机下的,网段也相同 ...
- ORACLE 关连更新 update select
总结: 关键的地方是where 语句的加入. 在11G中, 如果不加11G , 或造成除匹配的行数更新为相应的值之后, 其余的会变成负数. 所以, 测试的办法就是: 先查看需要更新的数量即连接的数 ...
- JAVA IDE下载地址
Subclipse 各版本官网下载地址: http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240 Eclipse ...
- Linux Install Node.js
1.下载node.js安装包,请参考网址:http://nodejs.org/download/ 在这个网址里面提供了几种node.js安装的方式 https://github.com/joyent/ ...
- Java中ArrayList源码分析
一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...
- 快速排序 javascript实现
Quicksort(快速排序) 是由 东尼·霍尔 所发展的一种排序. 它比其他的Ο(n log n)算法更快, 因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来.当然, ...