[C#/.NET]Entity Framework(EF) Code First 多對多關係的實體增,刪,改,查操做全程詳細示例

本文咱們來學習一下在Entity Framework中使用Context刪除多對多關係的實體是如何來實現的。咱們將以一個具體的控制檯小實例來了解和學習整個實現Entity Framework 多對多關係的實體刪除的操做過程。sql

你將學習到

  • 怎樣建立一個引用Entity Framework的項目;數據庫

  • 怎樣配置Entity Framework的數據庫鏈接;編程

  • 怎樣去掉Entity Framework Code First 生成的表名的複數;服務器

  • 怎樣經過EntityTypeConfiguartion<T>配置實體的Fluent API ;app

  • 怎樣配置Entity Framework的實體多對多的關係映射;ide

  • 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; }
    }
}

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; }
    }
}

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(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");
                });
        }
    }
}

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=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() }
            };
        }
    }
}

完成第一個命令和數據初始化配置後,咱們進行第二個命令。

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: 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.3 Update-Database -Verbose

執行以上命令,咱們這時再打開數據庫管理工具。沒錯ManyToManyRemoveDemo就在那裏。再查看錶是否成功生成呢,再檢查一下表中是否有咱們初始化的數據呢,沒錯,這些都是能夠有的。怎麼樣,驚喜吧,歡呼吧,咱們作到了!!!

entity-framework-remove-many-to-many-relationship-database.jpg

但還沒完,請先回復平靜,這還只是一個開始。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==3);
                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==2);
                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 = 4,
                    FirstName = "Console",
                    LastName = "App",
                    CreatedOn = DateTime.Now,
                    Roles = roles.Where(x => x.Id == 1).ToList()
                });
            }
        }

4.5 刪除多對多數據的示例

好了,以上是對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();
            }
        }

運行結果如圖:

完整示例代碼及下載地址

好了,最後把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 多對多關係的實體增,刪,改,查操做全程詳細示例

相關文章
相關標籤/搜索