首页 / 示例教程 / 正文

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

56039 发布于: 2015-12-04 读完约需48分钟
本文我们来学习一下在Entity Framework中使用Context删除多对多关系的实体是如何来实现的。我们将以一个具体的控制台小实例来了解和学习整个实现Entity Framework 多对多关系的实体删除的操作过程。

通过本文你将学习到:

  1. 怎样创建一个引用Entity Framework的项目;
  2. 怎样配置Entity Framework的数据库连接;
  3. 怎样去掉Entity Framework Code First 生成的表名的复数;
  4. 怎样通过EntityTypeConfiguartion<T>配置实体的Fluent API ;
  5. 怎样配置Entity Framework的实体多对多的关系映射;
  6. Entity Framework数据初始化;
  7. 怎样使用包管理工具控制台来生成和更新数据库;
  8. 怎么删除Entity Framework中的多对多关系的数据。
 

本示例开发环境:

操作系统:Windows 10 开发工具及版本:Visual Studio 2015 Update 1 .NET Framework版本:.NET Framework 4.6 程序输出方式:控制台应用程序  

一、创建项目

首先,我们创建一个控制台应用程序,取名为:EFRemoveManyToManyDemo entity-framework-remove-many-to-many-relationship-demo-environment 接着打开程序包管理工具,安装必须的EntityFramework引用包,如下: entity-framework-remove-many-to-many-relationship-demo 安装好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; }
    }
}
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; }
    }
}
为了配置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(50).IsRequired();
            Property(x => x.LastName).HasMaxLength(50).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(50).IsRequired();
            HasMany(x => x.Users)
                .WithMany(x => x.Roles)
                .Map(m =>
                {
                    m.MapLeftKey("RoleId");
                    m.MapRightKey("UserId");
                    m.ToTable("LNK_User_Role");
                });
        }
    }
}
接下来,我们再创建一个名为: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")
        {

        }
    }
}
再在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>
为了将我们刚才写的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所实体生成到配置好的数据库中。在接下来的过程中,我们会用到包管理控制台(Package Manager Console)和三个命令:

1.Enable-Migrations

命令使用方式如下图: entity-framework-remove-many-to-many-relationship-enable-migrations 运行以上命令后,Entity Framework会自动在我们的项目中创建一个名为Migrations的文件夹,同时生成一个Configuartion.cs的配置文件。这时的项目结构大致是这样的: entity-framework-remove-many-to-many-relationship-solution-enable-migrations 生成好的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)
        {

        }
    }
}
这里,我需要在生成数据库和表的时候添加一些初始数据到表中,我们就可以在Seed方法中来进行,如下:
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=1,Name="超级管理员" },
                new Role{ Id=2,Name="管理员" },
                new Role{ Id=3,Name="一般用户" }
            };

            var users = new List<User> {
                new User {Id=1,FirstName="Kobe",LastName="Bryant",CreatedOn=DateTime.Now,Roles=roles },
                 new User {Id=2,FirstName="Chris",LastName="Paul",CreatedOn=DateTime.Now,Roles=roles.Where(x=>x.Id==2).ToList() },
                 new User {Id=3,FirstName="Jerimy",LastName="Lin",CreatedOn=DateTime.Now,Roles=roles.Take(2).ToList() }
            };
        }
    }
}
完成第一个命令和数据初始化配置后,我们进行第二个命令。

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: 50),
                    })
                .PrimaryKey(t => t.Id);
            
            CreateTable(
                "dbo.User",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        FirstName = c.String(nullable: false, maxLength: 50),
                        LastName = c.String(nullable: false, maxLength: 50),
                        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.Update-Database -Verbose

执行以上命令,我们这时再打开数据库管理工具。没错ManyToManyRemoveDemo就在那里。再查看表是否成功生成呢,再检查一下表中是否有我们初始化的数据呢,没错,这些都是可以有的。怎么样,惊喜吧,欢呼吧,我们做到了!!! entity-framework-remove-many-to-many-relationship-database 但还没完,请先回复平静,这还只是一个开始。Entity Framework还可以做得更多,我们需要学习的也还有很多,编程的道路从来就不是一步到位的,得有个过程。一步一步往下看吧。 打开我们项目的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)));
                });
            }
        }
运行结果如图: entity-framework-remove-many-to-many-relationship-query 再来更新一条数据库中的数据怎么样,如下:
 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==3);
                user.FirstName = "ShuHao";
                cxt.SaveChanges();
            }
        }
运行结果如我们所料,如图: entity-framework-remove-many-to-many-relationship-update Id为3的User的FirstName已经从数据库更新了。同样的,我们要完成删除操作也比较简,如下:
 static void Remove()
        {
            using (var cxt = new ManyToManyRemoveContext())
            {
                var user = cxt.Users.FirstOrDefault(x=>x.Id==2);
                cxt.Users.Remove(user);
                cxt.SaveChanges();
            }
        }
就不再贴图了。最后是添加操作,向User表添加一个用户并分配一个Id为1的角色,代码如下:
static void Add()
        {
            List<Role> roles;
            using (var cxt = new ManyToManyRemoveContext())
            {
                roles = cxt.Roles.ToList();
                cxt.Users.Add(new User
                {
                    Id = 4,
                    FirstName = "Console",
                    LastName = "App",
                    CreatedOn = DateTime.Now,
                    Roles = roles.Where(x => x.Id == 1).ToList()
                });
            }
        }
好了,以上是对User(用户实体)进行简单的增、删、改、查的操作,那么我们要实现多对多的删除操作呢?也就是删除用户的同时删除其对应的角色,实现的代码如下:
static void RemoveManyToMany()
        {
            using (var cxt = new ManyToManyRemoveContext())
            {
                var user = cxt.Users.FirstOrDefault(x => x.Id == 1);
                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();
            }
        }
运行结果如图: entity-framework-remove-many-to-many-relationship-remove-many-to-many 好了,最后把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 = 4,
                    FirstName = "Console",
                    LastName = "App",
                    CreatedOn = DateTime.Now,
                    Roles = roles.Where(x => x.Id == 1).ToList()
                });
            }
        }

        static void Update()
        {
            using (var cxt = new ManyToManyRemoveContext())
            {
                var user = cxt.Users.FirstOrDefault(x => x.Id == 3);
                user.FirstName = "ShuHao";
                cxt.SaveChanges();
            }
        }

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

        static void RemoveManyToMany()
        {
            using (var cxt = new ManyToManyRemoveContext())
            {
                var user = cxt.Users.FirstOrDefault(x => x.Id == 1);
                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 多对多关系的实体增,删,改,查操作全程详细示例源码

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

上一篇: 国内前端框架Amaze UI 又发布新版啦-- v2.5.0

下一篇: [C#/.NET]Entity Framework(EF) Code First将实体中的string属性映射成text类型的几种方式

本文永久链接码友网 » [C#/.NET]Entity Framework(EF) Code First 多对多关系的实体增,删,改,查操作全程详细示例

分享扩散:

发表评论

登录用户才能发表评论, 请 登 录 或者 注册