【转载自https://segmentfault.com/a/1190000004152660】

[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例

本文我们来学习一下在Entity Framework中使用Context删除多对多关系的实体是如何来实现的。我们将以一个具体的控制台小实例来了解和学习整个实现Entity Framework 多对多关系的实体删除的操作过程。

你将学习到

  • 怎样创建一个引用Entity Framework的项目;

  • 怎样配置Entity Framework的数据库连接;

  • 怎样去掉Entity Framework Code First 生成的表名的复数;

  • 怎样通过EntityTypeConfiguartion<T>配置实体的Fluent API ;

  • 怎样配置Entity Framework的实体多对多的关系映射;

  • Entity Framework数据初始化;

  • 怎样使用包管理工具控制台来生成和更新数据库;

  • 怎么删除Entity Framework中的多对多关系的数据。

本示例开发环境

  • 操作系统:Windows 10

  • 开发工具及版本:Visual Studio 2015 Update 1

  • .NET Framework版本:.NET Framework 4.6

  • 程序输出方式:控制台应用程序

第一步、创建项目并引用程序包

1.1 创建项目

首先,我们创建一个控制台应用程序,取名为:EFRemoveManyToManyDemo,如下图:

1.2 引用程序包

接着打开程序包管理工具,安装必须的EntityFramework引用包,如下:

第二步、创建实体类并配置数据库连接

2.1 创建实体类

安装好Entity Framework包之后 ,我们先创建本示例需要的两个实体对应的类:User和Role(都放在Model的文件夹下),如下:

User.cs

 using System;
using System.Collections.Generic; namespace EFRemoveManyToManyDemo.Model
{
public class User
{
public User()
{
Roles = new HashSet<Role>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? CreatedOn { get; set; }
public virtual ICollection<Role> Roles { get; set; }//多对多关系中两边都要写上ICollection
}
}

Role.cs

 using System.Collections.Generic;

 namespace EFRemoveManyToManyDemo.Model
{
public class Role
{
public Role()
{
this.Users = new HashSet<User>();!!依赖注入中的构造器注入
}
public int Id { get; set; }
public string Name { get; set; } public virtual ICollection<User> Users { get; set; }
//多对多关系中两边都要写上ICollection
}
}

2.2 配置Fluent API

为了配置Fluent API,新建一个Mapping文件夹,再分别创建User的配置文件UserConfigurationMapping和Role的配置文件RoleConfigurationMapping,如下:

UserConfiguration.cs

using EFRemoveManyToManyDemo.Model;
using System.Data.Entity.ModelConfiguration; namespace EFRemoveManyToManyDemo.Mapping
{
public class UserConfigurationMapping : EntityTypeConfiguration<User>
{
public UserConfigurationMapping()
{
Property(x => x.FirstName).HasMaxLength().IsRequired();
Property(x => x.LastName).HasMaxLength().IsRequired();
}
}
}

RoleConfigurationMapping.cs

 using EFRemoveManyToManyDemo.Model;
using System.Data.Entity.ModelConfiguration; namespace EFRemoveManyToManyDemo.Mapping
{
public class RoleConfigurationMapping : EntityTypeConfiguration<Role>
{
public RoleConfigurationMapping()
{
HasKey(x => x.Id);
Property(x => x.Name).HasMaxLength().IsRequired();
HasMany(x => x.Users)
.WithMany(x => x.Roles)
.Map(m =>
{
m.MapLeftKey("RoleId");
m.MapRightKey("UserId");
m.ToTable("LNK_User_Role");
});
}
}
}

2.3 创建Context类

接下来,我们再创建一个名为:ManyToManyRemoveContext的类,该类继承至DbContext类,用于管理数据库的连接上下文和数据库初始化等的一些配置和操作,如下:

using EFRemoveManyToManyDemo.Mapping;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions; namespace EFRemoveManyToManyDemo
{
public class ManyToManyRemoveContext : DbContext
{
public ManyToManyRemoveContext() : base("ManyToManyRemoveContext")
{ }
}
}

2.4 配置连接字符串

再在App.config配置文件中添加本地的数据库连接字符串,大致如下(具体的请根据你的实际数据连接参数来):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
<connectionStrings>
<add name="ManyToManyRemoveContext" connectionString="server=你的数据库服务器地址;database=ManyToManyRemoveDemo;uid=你的数据库登录名;pwd=密码" providerName="System.Data.SqlClient"/>
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>

2.5 重写Context

为了将我们刚才写的Fluent API应用到对应的实体上,所以我们需要重写(override)DbContext的OnModelCreating方法,如下:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Configurations.Add(new UserConfigurationMapping());
modelBuilder.Configurations.Add(new RoleConfigurationMapping());
}

其中

modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

是将Entity Framework Code First在实体类生成对应表时去掉表名的复数用的。简单地说就是,默认情况下,Entity Framework Code First在由实体类生成对应表时的表名是复数形式的,比如本例的User和Role类,如果没有这句配置,在生成表名的时候将会是Users和Roles这两个表名,反之,则是User和Role这两个表名。

好了,下面贴出完整的ManyToManyRemoveContext.cs文件的代码:

 using EFRemoveManyToManyDemo.Mapping;
using EFRemoveManyToManyDemo.Model;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions; namespace EFRemoveManyToManyDemo
{
public class ManyToManyRemoveContext : DbContext
{
public ManyToManyRemoveContext() : base("ManyToManyRemoveContext")
{ } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Configurations.Add(new UserConfigurationMapping());
modelBuilder.Configurations.Add(new RoleConfigurationMapping());
} public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
}
}

本文写到这里,关于Entity Framework的引用,实体类的声明和Fluent API配置以及与数据库连接等操作都已完成了。接下来我们要做的是利用Entity Framework所实体生成到配置好的数据库中。

第三步、应用Migration生成数据库

在接下来的过程中,我们会用到包管理控制台(Package Manager Console)和三个命令:

3.1 Enable-Migrations

命令使用方式如下图:

运行以上命令后,Entity Framework会自动在我们的项目中创建一个名为Migrations的文件夹,同时生成一个Configuartion.cs的配置文件。这时的项目结构大致是这样的:

生成好Configuration.cs的文件我们再作数据的初始化,如下:

namespace EFRemoveManyToManyDemo.Migrations
{
using Model;
using System;
using System.Collections.Generic;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<ManyToManyRemoveContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
} protected override void Seed(ManyToManyRemoveContext context)
{
var roles = new List<Role> {
new Role{ Id=,Name="超级管理员" },
new Role{ Id=,Name="管理员" },
new Role{ Id=,Name="一般用户" }
}; var users = new List<User> {
new User {Id=,FirstName="Kobe",LastName="Bryant",CreatedOn=DateTime.Now,Roles=roles },
new User {Id=,FirstName="Chris",LastName="Paul",CreatedOn=DateTime.Now,Roles=roles.Where(x=>x.Id==).ToList() },
new User {Id=,FirstName="Jerimy",LastName="Lin",CreatedOn=DateTime.Now,Roles=roles.Take().ToList() }
};
}
}
}

完成第一个命令和数据初始化配置后,我们进行第二个命令。

3.2 Add-Migration Init -Verbose

执行此命令后,会在Migrations的文件夹中自动生成一个形如:时间戳_Init.cs的数据迁移文件,如本例生成的是201512040507219_Init.cs这样一个文件名,其中Init是我们指定的本次数据迁移的版本名称,文件中的内容如下:

 namespace EFRemoveManyToManyDemo.Migrations
{
using System;
using System.Data.Entity.Migrations; public partial class Init : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Role",
c => new
{
Id = c.Int(nullable: false, identity: true),
Name = c.String(nullable: false, maxLength: ),
})
.PrimaryKey(t => t.Id); CreateTable(
"dbo.User",
c => new
{
Id = c.Int(nullable: false, identity: true),
FirstName = c.String(nullable: false, maxLength: ),
LastName = c.String(nullable: false, maxLength: ),
CreatedOn = c.DateTime(),
})
.PrimaryKey(t => t.Id); CreateTable(
"dbo.LNK_User_Role",
c => new
{
RoleId = c.Int(nullable: false),
UserId = c.Int(nullable: false),
})
.PrimaryKey(t => new { t.RoleId, t.UserId })
.ForeignKey("dbo.Role", t => t.RoleId, cascadeDelete: true)
.ForeignKey("dbo.User", t => t.UserId, cascadeDelete: true)
.Index(t => t.RoleId)
.Index(t => t.UserId); } public override void Down()
{
DropForeignKey("dbo.LNK_User_Role", "UserId", "dbo.User");
DropForeignKey("dbo.LNK_User_Role", "RoleId", "dbo.Role");
DropIndex("dbo.LNK_User_Role", new[] { "UserId" });
DropIndex("dbo.LNK_User_Role", new[] { "RoleId" });
DropTable("dbo.LNK_User_Role");
DropTable("dbo.User");
DropTable("dbo.Role");
}
}
}

我们可以通过这个文件中的内容看到,有Up()和Down()这两个方法,Up()方法要执行的其实就是本次数据迁移要对数据进行的操作,而Down()方法则是在以后我们如果要退回到此版本应该执行的操作。

经过以上两个命令,如你迫不及待地要去数据库管理工具中查看有一个名叫:ManyToManyRemoveDemo的数据库是否已生成,那么很遗憾地告诉你,还没有。这时,我们还得执行最后一个命令来生成数据库和实体对应的表。

3.3 Update-Database -Verbose

执行以上命令,我们这时再打开数据库管理工具。没错ManyToManyRemoveDemo就在那里。再查看表是否成功生成呢,再检查一下表中是否有我们初始化的数据呢,没错,这些都是可以有的。怎么样,惊喜吧,欢呼吧,我们做到了!!!

但还没完,请先回复平静,这还只是一个开始。Entity Framework还可以做得更多,我们需要学习的也还有很多,编程的道路从来就不是一步到位的,得有个过程。一步一步往下看吧。

第四步、增、删、改、查操作

4.1 查询数据示例

打开我们项目的Program.cs文件。首先,我们来查询(Query)一下数据库中的数据,如下:

 static void Main(string[] args)
{
Query();
ReadKey();
} static void Query()
{
using (var cxt = new ManyToManyRemoveContext())
{
var users = cxt.Users.ToList();
users.ForEach(x =>
{
WriteLine("User First Name:{0},Last Name:{1},Create On:{2}\n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
});
}
}

运行结果如图:

4.2 更新数据示例

再来更新一条数据库中的数据怎么样,如下:

  static void Main(string[] args)
{
Update();
Query();
ReadKey();
} static void Query()
{
using (var cxt = new ManyToManyRemoveContext())
{
var users = cxt.Users.ToList();
users.ForEach(x =>
{
WriteLine("User First Name:{0},Last Name:{1},Create On:{2}\n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
});
}
} static void Update()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x=>x.Id==);
user.FirstName = "ShuHao";
cxt.SaveChanges();
}
}

运行结果如我们所料,如图:

4.3 删除数据示例

Id为3的User的FirstName已经从数据库更新了。同样的,我们要完成删除操作也比较简,如下:

  static void Remove()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x=>x.Id==);
cxt.Users.Remove(user);
cxt.SaveChanges();
}
}

4.4 新增数据示例

就不再贴图了。最后是添加操作,向User表添加一个用户并分配一个Id为1的角色,代码如下:

 static void Add()
{
List<Role> roles;
using (var cxt = new ManyToManyRemoveContext())
{
roles = cxt.Roles.ToList();
cxt.Users.Add(new User
{
Id = ,
FirstName = "Console",
LastName = "App",
CreatedOn = DateTime.Now,
Roles = roles.Where(x => x.Id == ).ToList()
});
}
}

4.5 删除多对多数据的示例

好了,以上是对User(用户实体)进行简单的增、删、改、查的操作,那么我们要实现多对多的删除操作呢?也就是删除用户的同时删除其对应的角色,实现的代码如下:

 static void RemoveManyToMany()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x => x.Id == );
var roles = new List<Role>();
roles.AddRange(user.Roles.Select(x => x));
foreach (var role in roles)
{
user.Roles.Remove(role);
}
cxt.Users.Remove(user);
cxt.SaveChanges();
}
}

运行结果如图:

完整示例代码及下载地址

好了,最后把Program.cs这个测试文件贴上来,供参考:

 using EFRemoveManyToManyDemo.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using static System.Console; namespace EFRemoveManyToManyDemo
{
public class Program
{
static void Main(string[] args)
{
//Update();
WriteLine("Before many to many removed");
Query();
RemoveManyToMany();
WriteLine("After many to many removed");
Query();
ReadKey();
} static void Query()
{
using (var cxt = new ManyToManyRemoveContext())
{
var users = cxt.Users.ToList();
users.ForEach(x =>
{
WriteLine("User First Name:{0},Last Name:{1},Create On:{2}\n |__Roles:{3}", x.FirstName, x.LastName, x.CreatedOn, string.Join(",", x.Roles.Select(r => r.Name)));
});
}
} static void Add()
{
List<Role> roles;
using (var cxt = new ManyToManyRemoveContext())
{
roles = cxt.Roles.ToList();
cxt.Users.Add(new User
{
Id = ,
FirstName = "Console",
LastName = "App",
CreatedOn = DateTime.Now,
Roles = roles.Where(x => x.Id == ).ToList()
});
}
} static void Update()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x => x.Id == );
user.FirstName = "ShuHao";
cxt.SaveChanges();
}
} static void Remove()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x => x.Id == );
cxt.Users.Remove(user);
cxt.SaveChanges();
}
} static void RemoveManyToMany()
{
using (var cxt = new ManyToManyRemoveContext())
{
var user = cxt.Users.FirstOrDefault(x => x.Id == );
var roles = new List<Role>();
roles.AddRange(user.Roles.Select(x => x));
foreach (var role in roles)
{
user.Roles.Remove(role);
}
cxt.Users.Remove(user);
cxt.SaveChanges();
}
}
}
}

【极力分享】[C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例【转载自https://segmentfault.com/a/1190000004152660】的更多相关文章

  1. [C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例

    本文我们来学习一下在Entity Framework中使用Context删除多对多关系的实体是如何来实现的.我们将以一个具体的控制台小实例来了解和学习整个实现Entity Framework 多对多关 ...

  2. Entity Framework 6 Code First 系列:无需修改实体和配置-在MySql中使用和SqlServer一致的并发控制

    无需修改实体和配置,在MySql中使用和SqlServer一致的并发控制.修改RowVersion类型不可取,修改为Timestamp更不可行.Sql Server的RowVersion生成一串唯一的 ...

  3. Entity Framework(EF) Code First将实体中的string属性映射成text类型的几种方式

    1.通过ColumnType属性设置 [Column(TypeName="text")] public string Text { get; set; } 在进行以上属性设置时,请 ...

  4. MVC EF 增 删 改 查

    using System;using System.Collections.Generic;using System.Linq;using System.Web;//using System.Data ...

  5. EF 如何更新多对多关系的实体

    ctx.Entry(user).Collection(t => t.UserPrivileges).Load(); Come form:https://www.thereformedprogra ...

  6. Entity Framework 6 Code First的简单使用和更新数据库结构

    一.安装Entity Framework 6 在项目中右击选择“管理NuGet程序包",联机搜索Entity Framework,点击安装 二.配置数据库连接 在App.config中加入数 ...

  7. Entity Framework 之 Code First

    使用NuGet助您玩转代码生成数据————Entity Framework 之 Code First [前言] 如果是Code First老鸟或者对Entity Framework不感兴趣,就不用浪费 ...

  8. 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表

    创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...

  9. ASP.NET Core 开发-Entity Framework (EF) Core 1.0 Database First

    ASP.NET Core 开发-Entity Framework Core 1.0 Database First,ASP.NET Core 1.0 EF Core操作数据库. Entity Frame ...

随机推荐

  1. CSS系列——前端进阶之路:初涉Less

    前言:最近帮一个朋友解决点问题,在查看组件源码的时候涉及到了less语法,这可难倒博主了.没办法,既然用到就要学呗,谁让咱是无所不能的程序猿呢!所以今天来学习下Less,算是笔记,也希望给初学less ...

  2. IO多路复用概念性

    sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...

  3. redis 命令

    添加数据 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo } span.s1 { } set key value //添加多条数据 ...

  4. HDF5基本使用方法

    HDF5, 大量(海量?)数据存储的一种解决方案. HDF的全称是Hiearchical Data Format, 5是版本号(未考证过TODO). 一个HDF5文件操作起来就像一个独立的文件系统. ...

  5. Scala中apply的用法

    Scala中的 apply 方法有着不同的含义, 对于函数来说该方法意味着调用function本身, 以下说明摘自Programming in Scala, 3rd Edition Every fun ...

  6. Oracle视图时间戳转为Date

    CREATE OR REPLACE VIEW PDAORDER AS SELECT po.id id, po.order_no AS order_no, po.money AS money, (SEL ...

  7. Android Stdio 调试Smali

    一 安装插件 1)Android stdio 安装插件 二 反编译smali 1)java -jar baksmali-2.1.2.jar app-debug.apk -o test/src2)and ...

  8. UVA1368

    用一个二维数组装m个字符串,然后用一个数组装每个字符串的hamming距离.找到最小的hanming距离即可 #include<stdio.h> #include<string.h& ...

  9. 【Beta】第七次任务发布

    PM #103 #85 日常管理&dev版宣传&新增报告管理后台. 后端 #103 报告管理后台后端实现,提供必要API接口及文档说明 验收:符合要求的接口及其说明文档 前端 #89 ...

  10. 18. class

    Class 基本用法 class n { constructor(x,y) { this.x = x; this.y = y; console.log(x,y) } proint() { consol ...