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 //生成對應的資料庫
其他常見指令如下圖:
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:*)