假设我们在程序中要用到的类的结构是这样的,这里比较特别的是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:如何实现一个主类中包含多个复类的更多相关文章

  1. 一个.java源文件中可以有多个类吗?(内部类除外)有什么条件?

    一个.java源文件中可以有多个类吗?(内部类除外)有什么条件?带着这个疑惑,动手建几个测试类, 揭开心中的疑惑.以下是解开疑惑过程: package test;/** * 一个.java源文件中可以 ...

  2. 当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出?

    当实体类中entity/DTO/VO等类中,有枚举值,应该怎么输出? 问题: orderStatus 和 payStatus都是枚举类,并且枚举的个数达地10来个,我们不可能在模板页面(jsp/ftl ...

  3. Path,Files巩固,题目:从键盘接收两个文件夹路径,把其中一个文件夹中(包含内容)拷贝到另一个文件夹中

    这个题目用传统的File,InputStream可以做,但是如果用Files,Path类做,虽然思路上会困难一些,但是代码简洁了很多,以下是代码: import java.io.IOException ...

  4. YTU 2618: B 求类中数据成员的最大值-类模板

    2618: B 求类中数据成员的最大值-类模板 时间限制: 1 Sec  内存限制: 128 MB 提交: 430  解决: 300 题目描述 声明一个类模板,类模板中有三个相同类型的数据成员,有一函 ...

  5. 对Integer类中的私有IntegerCache缓存类的一点记录

    对Integer类中的私有IntegerCache缓存类的一点记录 // Integer类有内部缓存,存贮着-128 到 127. // 所以,每个使用这些数字的变量都指向同一个缓存数据 // 因此可 ...

  6. 黑马基础阶段测试题:创建Phone(手机)类,Phone类中包含以下内容:

    package com.swift; public class Phone { private String pinpai; private int dianliang; public String ...

  7. 如何在其他类中实现继承自CFormView类的对象

    今天项目开发中,我们创建了一个对话框资源,并创建了一个派生自CFormView的类(假设为CMyClassDlg)来管理它. CMyClassDlg.h #pragma once // CMyClas ...

  8. 在JBPM的Handle类中调用Spring管理的类

    我们在使用JBPM定义流程的时候经常要在流程定义文件中加入一个继承xxxHandler的类来实现我们的业务逻辑判断或者其他的需求,在这个类中一般都是用Spring的Application来获取,而这种 ...

  9. String类中"=="、equals和普通类中"=="、equals的比较

    package cn.method.demo; public class StringDemo2 { public static void main(String[] args) { String s ...

随机推荐

  1. 使用WebView显示网页

    简单的页面跳转 package com.example.webtest; import java.security.PublicKey; import android.support.v7.app.A ...

  2. iOS 并行编程:Thread

    1 创建线程 1.1 NSThread       使用 NSThread 来创建线程有两个可以使用的方法: 1) 使用 detachNewThreadSelector:toTarget:withOb ...

  3. mysql mac 上启动

    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mariadb.plist 中内容: <string>/usr/local/o ...

  4. hdu 2027 统计元音

    统计元音 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  5. 解决PL/SQL Developer中文乱码的问题

    set nls_lang=SIMPLIFIED CHINESE_CHINA.ZHS16GBK cd "c:\Program Files\PLSQL Developer" PLSQL ...

  6. Yii框架页面运行流程

    Yii框架页面运行流程 CComponent | CModel | CActiveRecord.CFormModel(所有模型的父类) | 表名.php(模型) | 入口文件------------- ...

  7. 用 C# 如何判断数据库中是否存在一个值

    选定一个列,比如用户编号列 //欲插入的用户编号string ll_userID="xxxxxxxx"; //查询此编号是否存在SqlCommand mycmd = new Sql ...

  8. 在List中找出最大值的两种方法

    先说需求:找出一个对象List中,某个属性值最大的对象. 1.定义对象 private class A { public int ID { get; set; } public string Name ...

  9. string应用

    今天在网上搜了一些资料. C# string类应用 判断是否包含子串 想要判断一个字符串中是否包含某个子串,可以用Contains方法来实现: ? public bool Contains (stri ...

  10. (六)Hibernate 映射类型

    所有项目导入对应的hibernate的jar包.mysql的jar包和添加每次都需要用到的HibernateUtil.java 第一节:基本类型映射 例子: hibernate.cfg.xml < ...