數據庫設計
數據結構圖如下:
此次實例比較簡單,暫時只設計到上述3張表
SMUser:用於存儲用戶信息。
Role:用於存儲角色信息。
SMUser_Role:用建立用戶和角色關系的一直關聯表。
創建項目
開發工具:visual studio 2015
打開vs2015->新建項目->.NET Core->ASP.NET Core Application(.Net core)
如下圖:
給自己的項目取個名字,選個路徑,就完事了。
然后在自己創建的解決方案里再新增個類庫項目,此類庫項目用於實現數據庫的交互,也是實現EF Core的地方,如下圖:
我創建的項目結構如下圖所示:
之后便是引用的添加了:
App項目引用DAL
DAL項目使用Nuget添加以下引用:
Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityFrameworkCore.Tools
DAL實現
Entities
在DAL項目中新建Entities文件夾,該文件夾用於建立與數據庫表一一對應的實體類。我們根據數據庫結構,創建一下3個實體類。
SMUser:
using System; using System.Collections.Generic; namespace SnmiOA.DAL.Entities { public class SMUser { public Guid SMUserId { get; set; } public string SSOUserName { get; set; } public string SSOPassword { get; set; } public string TrueName { get; set; } public bool IsValid { get; set; } public string Mobile { get; set; } public string Email { get; set; } public string UserNo { get; set; } public string EmployeeNo { get; set; } public string QQ { get; set; } public virtual ICollection<SMUserRole> SMUserRoles { get; set; } } }
Role:
using System; using System.Collections.Generic; namespace SnmiOA.DAL.Entities { public class Role { public Guid RoleId { get; set; } public string RoleName { get; set; } public int OrderField { get; set; } public virtual ICollection<SMUserRole> SMUserRoles { get; set; } } }
SMUserRole:
using System; namespace SnmiOA.DAL.Entities { public class SMUserRole { public Guid SMUserId { get; set; } public Guid RoleId { get; set; } public virtual Role Role { get; set; } public virtual SMUser SMUser { get; set; } } }
DbContext實現
在DAL項目下添加SnmiOAContext.cs文件。其代碼如下:
public class SnmiOAContext : DbContext { public SnmiOAContext(DbContextOptions<SnmiOAContext> options) : base(options) { } public DbSet<SMUser> SMUsers { get; set; } public DbSet<Role> Roles { get; set; } public DbSet<SMUserRole> SMUserRoles { get; set; } }
然后我們需要添加一下3張表之間的映射關系,通過表結構可以看出來,實際上我們的SMUser和Role之間是多對多的關系,SMUser_Role是兩張表產生的一張中間表,在以前的EF中這兩張表可以直接映射多對多的關系。但是在EF Core中目前我還沒有發現這種映射關系的寫法,可能是我閱讀的資料還不夠,也可能是真的沒有提供這種映射。后來我就找到個把他們都分別改成一對多的關系來寫,發現也是可以的。代碼如下:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<SMUserRole>() .ToTable("SMUser_Role") .HasKey(ur => new { ur.RoleId, ur.SMUserId }); modelBuilder.Entity<SMUserRole>() .HasOne(ur => ur.SMUser) .WithMany(u => u.SMUserRoles) .HasForeignKey(ur => ur.SMUserId); modelBuilder.Entity<SMUserRole>() .HasOne(ur => ur.Role) .WithMany(r => r.SMUserRoles) .HasForeignKey(ur => ur.RoleId); modelBuilder.Entity<SMUser>() .ToTable("SMUser") .HasKey(u => u.SMUserId); modelBuilder.Entity<SMUser>() .HasMany(u => u.SMUserRoles) .WithOne(ur => ur.SMUser) .HasForeignKey(u => u.SMUserId); modelBuilder.Entity<Role>() .ToTable("Role") .HasKey(r => r.RoleId); modelBuilder.Entity<Role>() .HasMany(r => r.SMUserRoles) .WithOne(ur => ur.Role) .HasForeignKey(ur => ur.RoleId); }
如果大家有更好的方法,還請告知,謝謝!
最后,別忘記了DBContext的依賴注入。
我們在APP項目的StartUp文件的ConfigureServices方法中添加以下代碼:
services.AddDbContext<SnmiOAContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SnmiOAConnection")));
整體看上去應該是這樣:
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddApplicationInsightsTelemetry(Configuration); services.AddDbContext<SnmiOAContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SnmiOAConnection"))); services.AddMvc(); }
Repository實現
當我們使用不同的數據模型和領域模型時,倉儲模式特別有用。倉儲可以充當數據模型和領域模型之間的中介。在內部,倉儲以數據模型的形式和數據庫交互,然后給數據訪問層之上的應用層返回領域模型。
在我們這個例子中,因為使用了數據模型作為領域模型,因此,也會返回相同的模型。如果想要使用不同的數據模型和領域模型,那么需要將數據模型的值映射到領域模型或使用任何映射庫執行映射。
現在定義倉儲接口IRepository如下:
using System; using System.Linq; using System.Linq.Expressions; namespace SnmiOA.DAL.Repository { public interface IRepository<T> where T :class { IQueryable<T> GetAllList(Expression<Func<T, bool>> predicate = null); T Get(Expression<Func<T, bool>> predicate); void Insert(T entity); void Delete(T entity); void Update(T entity); long Count(); } }
上面的幾個方法都是常見的CRUD操作,就不解釋了.
然后再實現一個倉儲類的泛型基類,用來實現IRepository接口,代碼如下:
using Microsoft.EntityFrameworkCore; using System; using System.Linq; using System.Linq.Expressions; namespace SnmiOA.DAL.Repository { public class RepositoryBase<T> : IRepository<T> where T : class { private readonly SnmiOAContext _context = null; private readonly DbSet<T> _dbSet; public RepositoryBase(SnmiOAContext context) { _context = context; _dbSet = _context.Set<T>(); } public long Count() { return _dbSet.LongCount(); } public void Delete(T entity) { _dbSet.Remove(entity); } public T Get(Expression<Func<T, bool>> predicate) { return _dbSet.FirstOrDefault(predicate); } public IQueryable<T> GetAllList(Expression<Func<T, bool>> predicate = null) { if (predicate == null) { return _dbSet; } return _dbSet.Where(predicate); } public void Insert(T entity) { _dbSet.Add(entity); } public void Update(T entity) { _dbSet.Attach(entity); _context.Entry(entity).State = EntityState.Modified; } } }
這樣每個實體類的倉儲類實現起來,就非常簡單了,如下:
using SnmiOA.DAL.Entities; namespace SnmiOA.DAL.Repository { public class RoleRepository : RepositoryBase<Role> { public RoleRepository(SnmiOAContext context) : base(context) { } } }
再安裝上述代碼分別為SMUser和SMUserRole建立倉儲類,如果需要更復雜的數據庫查詢操作,可以上上述倉儲類中補充實現。
UnitOfWork實現
我們已經知道,DbContext默認支持事務,當實例化一個新的DbContext對象時,就會創建一個新的事務,當調用SaveChanges方法時,事務會提交。問題是,如果我們使用相同的DbContext對象把多個代碼模塊的操作放到一個單獨的事務中,該怎么辦呢?答案就是工作單元(Unit of Work)。
工作單元本質是一個類,它可以在一個事務中跟蹤所有的操作,然后將所有的操作作為原子單元執行。看一下倉儲類,可以看到DbContext對象是從外面傳給它們的。此外,所有的倉儲類都沒有調用SaveChanges方法,原因在於,我們在創建工作單元時會將DbContext對象傳給每個倉儲。當想保存修改時,就可以在工作單元上調用SaveChanges方法,也就在DbContext類上調用了SaveChanges方法。這樣就會使得涉及多個倉儲的所有操作成為單個事務的一部分。
這里定義我們的工作單元類如下:
using SnmiOA.DAL.Repository; using System; namespace SnmiOA.DAL { public class UnitOfWork : IDisposable { private readonly SnmiOAContext _context = null; private SMUserRepository _userRepository = null; private SMUserRoleRepository _userRoleRepository = null; private RoleRepository _roleRepository = null; public UnitOfWork(SnmiOAContext context) { _context = context; } public SMUserRepository SMUserRepository { get { return _userRepository ?? (_userRepository = new SMUserRepository(_context)); } } public SMUserRoleRepository SMUserRoleRepository { get { return _userRoleRepository ?? (_userRoleRepository = new SMUserRoleRepository(_context)); } } public RoleRepository RoleRepository { get { return _roleRepository ?? (_roleRepository = new RoleRepository(_context)); } } public void SaveChanges() { _context.SaveChanges(); } public void Dispose() { throw new NotImplementedException(); } } }
完
作者:ChainZhang
鏈接:https://www.jianshu.com/p/292d0eeb8afb
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。
