本文為轉(zhuǎn)載牧挣,原文:asp.net core 實(shí)戰(zhàn)項(xiàng)目(一)——ef core的使用
數(shù)據(jù)庫設(shè)計(jì)
數(shù)據(jù)結(jié)構(gòu)圖如下:
此次實(shí)例比較簡單靡砌,暫時(shí)只設(shè)計(jì)到上述3張表
SMUser:用于存儲用戶信息廊鸥。
Role:用于存儲角色信息。
SMUser_Role:用建立用戶和角色關(guān)系的一直關(guān)聯(lián)表。
創(chuàng)建項(xiàng)目
開發(fā)工具:visual studio 2015
打開vs2015->新建項(xiàng)目->.NET Core->ASP.NET Core Application(.Net core)
如下圖:
給自己的項(xiàng)目取個(gè)名字,選個(gè)路徑诉稍,就完事了。
然后在自己創(chuàng)建的解決方案里再新增個(gè)類庫項(xiàng)目最疆,此類庫項(xiàng)目用于實(shí)現(xiàn)數(shù)據(jù)庫的交互杯巨,也是實(shí)現(xiàn)EF Core的地方,如下圖:
我創(chuàng)建的項(xiàng)目結(jié)構(gòu)如下圖所示:
之后便是引用的添加了:
App項(xiàng)目引用DAL
DAL項(xiàng)目使用Nuget添加以下引用:
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
DAL實(shí)現(xiàn)
Entities
在DAL項(xiàng)目中新建Entities文件夾努酸,該文件夾用于建立與數(shù)據(jù)庫表一一對應(yīng)的實(shí)體類服爷。我們根據(jù)數(shù)據(jù)庫結(jié)構(gòu),創(chuàng)建一下3個(gè)實(shí)體類。
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實(shí)現(xiàn)
在DAL項(xiàng)目下添加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張表之間的映射關(guān)系心褐,通過表結(jié)構(gòu)可以看出來,實(shí)際上我們的SMUser和Role之間是多對多的關(guān)系笼踩,SMUser_Role是兩張表產(chǎn)生的一張中間表檬寂,在以前的EF中這兩張表可以直接映射多對多的關(guān)系。但是在EF Core中目前我還沒有發(fā)現(xiàn)這種映射關(guān)系的寫法戳表,可能是我閱讀的資料還不夠,也可能是真的沒有提供這種映射昼伴。后來我就找到個(gè)把他們都分別改成一對多的關(guān)系來寫匾旭,發(fā)現(xiàn)也是可以的。代碼如下:
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項(xiàng)目的StartUp文件的ConfigureServices方法中添加以下代碼:
services.AddDbContext<SnmiOAContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SnmiOAConnection")));
整體看上去應(yīng)該是這樣:
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<SnmiOAContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("SnmiOAConnection")));
services.AddMvc();
}
Repository實(shí)現(xiàn)
當(dāng)我們使用不同的數(shù)據(jù)模型和領(lǐng)域模型時(shí),倉儲模式特別有用逸寓。倉儲可以充當(dāng)數(shù)據(jù)模型和領(lǐng)域模型之間的中介居兆。在內(nèi)部,倉儲以數(shù)據(jù)模型的形式和數(shù)據(jù)庫交互竹伸,然后給數(shù)據(jù)訪問層之上的應(yīng)用層返回領(lǐng)域模型泥栖。
在我們這個(gè)例子中,因?yàn)槭褂昧藬?shù)據(jù)模型作為領(lǐng)域模型勋篓,因此吧享,也會返回相同的模型。如果想要使用不同的數(shù)據(jù)模型和領(lǐng)域模型譬嚣,那么需要將數(shù)據(jù)模型的值映射到領(lǐng)域模型或使用任何映射庫執(zhí)行映射钢颂。
現(xiàn)在定義倉儲接口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();
}
}
上面的幾個(gè)方法都是常見的CRUD操作,就不解釋了.
然后再實(shí)現(xiàn)一個(gè)倉儲類的泛型基類拜银,用來實(shí)現(xiàn)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;
}
}
}
這樣每個(gè)實(shí)體類的倉儲類實(shí)現(xiàn)起來,就非常簡單了盐股,如下:
using SnmiOA.DAL.Entities;
namespace SnmiOA.DAL.Repository
{
public class RoleRepository : RepositoryBase<Role>
{
public RoleRepository(SnmiOAContext context) : base(context)
{
}
}
}
再安裝上述代碼分別為SMUser和SMUserRole建立倉儲類钱豁,如果需要更復(fù)雜的數(shù)據(jù)庫查詢操作,可以上上述倉儲類中補(bǔ)充實(shí)現(xiàn)疯汁。
UnitOfWork實(shí)現(xiàn)
我們已經(jīng)知道牲尺,DbContext默認(rèn)支持事務(wù),當(dāng)實(shí)例化一個(gè)新的DbContext對象時(shí),就會創(chuàng)建一個(gè)新的事務(wù)谤碳,當(dāng)調(diào)用SaveChanges方法時(shí)溃卡,事務(wù)會提交。問題是蜒简,如果我們使用相同的DbContext對象把多個(gè)代碼模塊的操作放到一個(gè)單獨(dú)的事務(wù)中瘸羡,該怎么辦呢?答案就是工作單元(Unit of Work)搓茬。
工作單元本質(zhì)是一個(gè)類犹赖,它可以在一個(gè)事務(wù)中跟蹤所有的操作,然后將所有的操作作為原子單元執(zhí)行卷仑【澹看一下倉儲類,可以看到DbContext對象是從外面?zhèn)鹘o它們的锡凝。此外粘昨,所有的倉儲類都沒有調(diào)用SaveChanges方法,原因在于窜锯,我們在創(chuàng)建工作單元時(shí)會將DbContext對象傳給每個(gè)倉儲张肾。當(dāng)想保存修改時(shí),就可以在工作單元上調(diào)用SaveChanges方法锚扎,也就在DbContext類上調(diào)用了SaveChanges方法吞瞪。這樣就會使得涉及多個(gè)倉儲的所有操作成為單個(gè)事務(wù)的一部分。
這里定義我們的工作單元類如下:
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();
}
}
}
完
本文為原創(chuàng)工秩,轉(zhuǎn)載請注明出處