天天看點

EFCore初探一、如何使用DBFirst二、如何在CodeFirst中做資料遷移三、如何延遲加載四、表關系映射五、源碼下載下傳總結

EFCore初探

  • 一、如何使用DBFirst
    • 1.引入包
    • 2.程式包控制台執行
    • 3.添加日志架構
  • 二、如何在CodeFirst中做資料遷移
    • 1.定義資料庫實體模型
    • 2.定義DBContext
    • 3.引入包
    • 4.在程式包管理控制台執行如下指令
    • 5.重建DB
  • 三、如何延遲加載
    • 1.引入包
    • 2.測試樣例
  • 四、表關系映射
    • 1.一對一關系映射
    • 2.一對多關系映射
    • 3.多對多關系映射
  • 五、源碼下載下傳
  • 總結

一、如何使用DBFirst

1.引入包

代碼如下(示例):

Microsoft.EntityFrameworkCore 
Microsoft.EntityFrameworkCore.Design 
Microsoft.EntityFrameworkCore.SqlServer 
Microsoft.EntityFrameworkCore.SqlServer.Design 
Microsoft.EntityFrameworkCore.Tools
           

2.程式包控制台執行

代碼如下(示例):

經過以上兩個步驟就可以根據資料自動生成Entities實體模型和DBContext

3.添加日志架構

代碼如下(示例):

加入包

Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console
           

定義日志工廠

注入工廠

二、如何在CodeFirst中做資料遷移

1.定義資料庫實體模型

實體中必須聲明主鍵(Id預設被認為是主鍵)

代碼如下(示例):

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

#nullable disable

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class Category
    {
        public Category()
        {
            Products = new HashSet<Product>();
        }
        [Key]
        [Required]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Desc { get; set; }

        public virtual ICollection<Product> Products { get; set; }
    }
}

           

代碼如下(示例):

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

#nullable disable

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class Product
    {
        public Product()
        {
            Orders = new HashSet<Order>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public string Desc { get; set; }
        public int CatetoryId { get; set; }
        public bool Discontinued { get; set; }
        [Required]
        [MaxLength(100)]
        public string Url { get; set; }

        public virtual Category Catetory { get; set; }
        public virtual ICollection<Order> Orders { get; set; }
    }
}

           

代碼如下(示例):

using System;
using System.Collections.Generic;

#nullable disable

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class Client
    {
        public Client()
        {
            Orders = new HashSet<Order>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Tel { get; set; }
        public bool? Sex { get; set; }
        public string Address { get; set; }
        public DateTime CreateTime { get; set; }
        public int CreatorId { get; set; }
        public string City { get; set; }

        public virtual ICollection<Order> Orders { get; set; }
    }
}

           

代碼如下(示例):

using System;
using System.Collections.Generic;

#nullable disable

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class Order
    {
        public int Id { get; set; }
        public int ClientId { get; set; }
        public int ProductId { get; set; }
        public int Amount { get; set; }
        public decimal Price { get; set; }
        public DateTime CreateTime { get; set; }
        public int CreatorId { get; set; }
        public string ShipCity { get; set; }

        public virtual Client Client { get; set; }
        public virtual Product Product { get; set; }
    }
}

           

代碼如下(示例):

using System;
using System.Collections.Generic;
using System.Text;

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class UserLog
    {
        public int Id { get; set; }
        public string UserName { get; set; }

        public byte LogType { get; set; }
        public virtual UserLogDetail UserLogDetail { get; set; }
    }
}

           

代碼如下(示例):

using System;
using System.Collections.Generic;
using System.Text;

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class UserLogDetail
    {
        public int Id { get; set; }

        public string Introduction { get; set; }
        public string Detail { get; set; }
        public byte LogType { get; set; }
        public int CreatorId { get; set; }
        public int? LastModifierId { get; set; }
        public DateTime? LastModifyTime { get; set; }
        public DateTime CreateTime { get; set; }
    }
}

           

2.定義DBContext

代碼如下(示例):

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.Extensions.Logging;

#nullable disable

namespace EFCoreDemo.CodeFirst.Migrations.Entities
{
    public partial class EFCodeFirstDemoContext : DbContext
    {
        public static ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
        //導航屬性:引用屬性和集合屬性
        //HasOne:自己引用誰(引用屬性,表本身和表裡面有哪些外鍵對象,關系是1:1)
        //WithMany:自己被誰引用(集合屬性,表裡面的外鍵對象和表本身,關系是1:*)
        public EFCodeFirstDemoContext()
        {
            
        }

        public EFCodeFirstDemoContext(DbContextOptions<EFCodeFirstDemoContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Category> Categories { get; set; }
        public virtual DbSet<Client> Clients { get; set; }
        public virtual DbSet<Order> Orders { get; set; }
        public virtual DbSet<Product> Products { get; set; }

        public virtual DbSet<UserLog> UserLog { get; set; }
        public virtual DbSet<UserLogDetail> UserLogDetail { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
                optionsBuilder.UseLazyLoadingProxies()
                    .UseSqlServer("Server=.;Database=EFCoreCodeFirstDemo;uid=sa;pwd=Lykj20190325");
            }
            optionsBuilder.UseLoggerFactory(MyLoggerFactory);

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasAnnotation("Relational:Collation", "Chinese_PRC_CI_AS");

            modelBuilder.Entity<Category>(entity =>
            {
                entity.ToTable("Category");

                entity.Property(e => e.Id).ValueGeneratedNever();

                entity.Property(e => e.Desc).HasMaxLength(50);

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(50);
            });

            modelBuilder.Entity<Client>(entity =>
            {
                entity.ToTable("Client");

                entity.Property(e => e.Address).HasMaxLength(100);

                entity.Property(e => e.City).HasMaxLength(50);

                entity.Property(e => e.CreateTime)
                    .HasColumnType("datetime")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(20);

                entity.Property(e => e.Tel)
                    .IsRequired()
                    .HasMaxLength(11);
            });

            modelBuilder.Entity<Order>(entity =>
            {
                entity.ToTable("Order");

                entity.Property(e => e.CreateTime)
                    .HasColumnType("datetime")
                    .HasDefaultValueSql("(getdate())");

                entity.Property(e => e.Price).HasColumnType("decimal(18, 2)");

                entity.Property(e => e.ShipCity).HasMaxLength(50);

                entity.HasOne(d => d.Client)
                    .WithMany(p => p.Orders)
                    .HasForeignKey(d => d.ClientId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("fk_order_client");

                entity.HasOne(d => d.Product)
                    .WithMany(p => p.Orders)
                    .HasForeignKey(d => d.ProductId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("fk_order_product");
            });

            modelBuilder.Entity<Product>(entity =>
            {
                entity.ToTable("Product");

                entity.Property(e => e.Desc).HasMaxLength(200);

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(50);

                entity.Property(e => e.Price).HasColumnType("decimal(18, 2)");

                entity.HasOne(d => d.Catetory)
                    .WithMany(p => p.Products)
                    .HasForeignKey(d => d.CatetoryId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("fk_Product_Category");
            });

            modelBuilder.Entity<UserLog>(entity => {
                entity.Property(e => e.UserName)
                .IsRequired().HasMaxLength(20);
            });



            //表拆分
            modelBuilder.Entity<UserLog>(entity => {
                entity.ToTable("UserLogInfo");
                entity.Property(o => o.LogType).HasColumnName("LogType");//配置兩個實體的相同屬性映射到表的同一列
                entity.HasOne(o => o.UserLogDetail).WithOne().HasForeignKey<UserLog>(o => o.Id);
            });
            modelBuilder.Entity<UserLogDetail>(entity => {
                entity.ToTable("UserLogInfo");
                entity.Property(o => o.LogType).HasColumnName("LogType");//配置兩個實體的相同屬性映射到表的同一列
            });
            OnModelCreatingPartial(modelBuilder);
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

           

3.引入包

代碼如下(示例):

Microsoft.EntityFrameworkCore 
Microsoft.EntityFrameworkCore.Design 
Microsoft.EntityFrameworkCore.SqlServer 
Microsoft.EntityFrameworkCore.SqlServer.Design 
Microsoft.EntityFrameworkCore.Tools
Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console
           

4.在程式包管理控制台執行如下指令

add-migration migrationname   //生成遷移檔案
update-database  //生成對應的資料庫
           

其他常見指令如下圖:

EFCore初探一、如何使用DBFirst二、如何在CodeFirst中做資料遷移三、如何延遲加載四、表關系映射五、源碼下載下傳總結

5.重建DB

代碼如下(示例):

context.Database.EnsureDeleted(); //删除資料庫
context.Database.EnsureCreated(); //建立資料庫和表
           

三、如何延遲加載

1.引入包

EFCore 預設是不支援導航屬性的,若有支援必須引入Microsoft.EntityFrameworkCore.Proxies包

代碼如下(示例):

optionsBuilder.UseLazyLoadingProxies()
                    .UseSqlServer("Server=.;Database=EFCoreCodeFirstDemo;uid=sa;pwd=Lykj20190325");
           

2.測試樣例

代碼如下(示例):

public static void TestNavigation()
        {
            using (EFCodeFirstDemoContext ctx = new EFCodeFirstDemoContext()) //EFCore 預設是不支援導航屬性的,若有支援必須引入Microsoft.EntityFrameworkCore.Proxies包
            {
                Client client = ctx.Clients.Find(3);
                var clientList = ctx.Clients.Where(c => c.Id > 0);
                foreach (var item in clientList)
                {
                    Console.WriteLine(item.Name);
                    foreach (var order in item.Orders)//這裡并不會生成Sql去查詢相應的order(若沒有配置延遲加載)
                    {
                        Console.WriteLine(order.Price);
                    }
                }
            }
            using (EFCodeFirstDemoContext ctx = new EFCodeFirstDemoContext())//
            {
                var clientList = ctx.Clients.Include(c => c.Orders);
                foreach (var item in clientList)
                {
                    Console.WriteLine(item.Name);
                }
            }

            using (EFCodeFirstDemoContext ctx = new EFCodeFirstDemoContext())
            {
                var proList = ctx.Products.Include(p => p.Catetory);
                foreach (var item in proList)
                {
                    Console.WriteLine(item.Catetory.Name);
                }
            }
        }
           

四、表關系映射

1.一對一關系映射

比如表拆分,上面模型的UserLog和UserLogDetail合并為一個UserLogInfo資料表

背景配置示例代碼如下:

modelBuilder.Entity<UserLog>(entity => {
                entity.ToTable("UserLogInfo");
                entity.Property(o => o.LogType).HasColumnName("LogType");//配置兩個實體的相同屬性映射到表的同一列
                entity.HasOne(o => o.UserLogDetail).WithOne().HasForeignKey<UserLog>(o => o.Id);
            });
            modelBuilder.Entity<UserLogDetail>(entity => {
                entity.ToTable("UserLogInfo");
                entity.Property(o => o.LogType).HasColumnName("LogType");//配置兩個實體的相同屬性映射到表的同一列
            });
           

上端調用示例代碼如下:

public static void TestTableSplit()
        {
            using (EFCodeFirstDemoContext ctx = new EFCodeFirstDemoContext())
            {
                UserLog userLog = new UserLog()
                {
                    LogType = new byte(),
                    UserName="Fisea",
                    UserLogDetail = new UserLogDetail()
                    {
                        CreateTime=DateTime.Now,
                        LogType= new byte(),
                        CreatorId=1,
                        Detail="sflsflsdfj",
                        Introduction="this is a test",
                        LastModifierId=1,
                        LastModifyTime=DateTime.Now
                    }
                };
                ctx.UserLog.Add(userLog);
                ctx.SaveChanges();

               var log=  ctx.UserLog.Find(1);
                var log1 = ctx.UserLog.FirstOrDefault(l => l.Id == 1);
                var log2 = ctx.UserLog.Include(l => l.UserLogDetail).FirstOrDefault(l => l.Id == 2);
            }
        }
           

2.一對多關系映射

WithMany:自己被誰引用(集合屬性,表裡面的外鍵對象和表本身,關系是1:*)

3.多對多關系映射

典型的例子就是User和Role之間的關系

五、源碼下載下傳

下載下傳

總結

導航屬性:可以分為引用屬性和集合屬性

HasOne:自己引用誰(引用屬性, 表本身和表裡面有哪些外鍵對象,關系是1:1)

WithMany:自己被誰引用(集合屬性,表裡面的外鍵對象和表本身,關系是1:*)

繼續閱讀