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 ...
随机推荐
- Linux环境下搭建Android开发环境
最近在折腾linux.因为咱是搞安卓开发的,所以少不了需要搭建Android开发环境,就此小记,希望能给向我一样的开发者一点帮助!开干! 1.安装JDK 下载JDK包,得到的是类似于jdk-8u65- ...
- arc项目中使用非arc文件
因为之前没有ARC机制,好多比较好的类库都是使用的非ARC,或是有些大牛还是不喜欢用ARC,封装的类也是非ARC的,想要在自己的ARC项目中使用这些非ARC类库,只需要简单的设置一下就可以了. 1.在 ...
- SMTP ERROR: Password command failed: 535 Incorrect authentication data
在处理一个使用PHPMailer来发送电邮,我在本地使用我的163邮箱来做测试发送电邮,能够成功的发送电邮:当上传到正式平台时,出现了,类似这样的错误信息 SMTP ERROR: Password c ...
- sklearn两种保存模型的方式
作者:卢嘉颖 链接:https://www.zhihu.com/question/27187105/answer/97334347 来源:知乎 著作权归作者所有,转载请联系作者获得授权. 1. pic ...
- js事件3
一.loading——(用来加载位于网页中的文件,而非本地的) 例子: <!doctype html> <html lang="en"> <head& ...
- 图解JVM在内存中申请对象及垃圾回收流程
http://longdick.iteye.com/blog/468368 先看一下JVM的内存模型: 从大的方面来讲,JVM的内存模型分为两大块: 永久区内存( Permanent space )和 ...
- 替换SQL Server数据库中所有表的所有字段的某些内容
declare @t varchar(255),@c varchar(255) declare table_cursor cursor for select a.name,b.name from ...
- SQL 有父标识的 递归查询
递归查询,临时表的高级应用 WITH temp AS ( --父项 SELECT * FROM Ar_Area WHERE Ar_Parent = UNION ALL --递归结果集中的下级 SELE ...
- EF的TransactionScope
TransactionScope是一个分布式事务的语句块,被包含起来的语句一起被提交,当出现异常,一起回滚,这都是托管的 当Web没有开启MSDTC服务时候会出现:
- UIView的frame和bounds区别
UIView的frame和bounds区别 iOS中,大家肯定对view和frame都不陌生,我们设置view在父view中的位置和大小时,只需要设置frame就可以了. 可能大家也有查过网上的一些资 ...