数据库设计

数据结构图如下:

 

此次实例比较简单,暂时只设计到上述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
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

asp.net core 实战项目(一)——ef core的使用的更多相关文章

  1. .NET Core实战项目之CMS 第二章 入门篇-快速入门ASP.NET Core看这篇就够了

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9985451.html 本来这篇只是想简单介绍下ASP.NET Core MVC项目的(毕竟要照顾到很多新 ...

  2. ASP.NET Core 开发-Entity Framework (EF) Core 1.0 Database First

    ASP.NET Core 开发-Entity Framework Core 1.0 Database First,ASP.NET Core 1.0 EF Core操作数据库. Entity Frame ...

  3. ASP.NET Core 开发 - Entity Framework (EF) Core

    EF Core 1.0 Database First http://www.cnblogs.com/linezero/p/EFCoreDBFirst.html ASP.NET Core 开发 - En ...

  4. .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9977862.html 写在前面 千呼万唤始出来,首先,请允许我长吸一口气!真没想到一份来自28岁老程序员 ...

  5. .NET Core实战项目之CMS 第三章 入门篇-源码解析配置文件及依赖注入

    作者:依乐祝 原文链接:https://www.cnblogs.com/yilezhu/p/9998021.html 写在前面 上篇文章我给大家讲解了ASP.NET Core的概念及为什么使用它,接着 ...

  6. .NET Core实战项目之CMS 第四章 入门篇-Git的快速入门及实战演练

    写在前面 上篇文章我带着大家通过分析了一遍ASP.NET Core的源码了解了它的启动过程,然后又带着大家熟悉了一遍配置文件的加载方式,最后引出了依赖注入以及控制反转的概念!如果大家把前面几张都理解了 ...

  7. .NET Core实战项目之CMS 第五章 入门篇-Dapper的快速入门看这篇就够了

    写在前面 上篇文章我们讲了如在在实际项目开发中使用Git来进行代码的版本控制,当然介绍的都是比较常用的功能.今天我再带着大家一起熟悉下一个ORM框架Dapper,实例代码的演示编写完成后我会通过Git ...

  8. .NET Core实战项目之CMS 第六章 入门篇-Vue的快速入门及其使用

    写在前面 上面文章我给大家介绍了Dapper这个ORM框架的简单使用,大伙会用了嘛!本来今天这篇文章是要讲Vue的快速入门的,原因是想在后面的文章中使用Vue进行这个CMS系统的后台管理界面的实现.但 ...

  9. .NET Core实战项目之CMS 第七章 设计篇-用户权限极简设计全过程

    写在前面 这篇我们对用户权限进行极简设计并保留其扩展性.首先很感谢大家的阅读,前面六章我带着大家快速入门了ASP.NET Core.ASP.NET Core的启动过程源码解析及配置文件的加载过程源码解 ...

  10. .NET Core实战项目之CMS 第九章 设计篇-白话架构设计

    前面两篇文章给大家介绍了我们实战的CMS系统的数据库设计,源码也已经上传到服务器上了.今天我们就好聊聊架构设计,在开始之前先给大家分享一下这几天我一直在听的<从零开始学架构>里面关于架构设 ...

随机推荐

  1. 括号生成(Java实现)

    题目: 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n =3,生成结果为: [ "((()))", "(()( ...

  2. Linux 缩减逻辑卷

    因工作需要,将/usr/users 空间从100G 缩小到50G 检查文件系统类型 mount | grep  /usr/users 发现该文件系统使用的是 xfs  ,逻辑卷为 /dev/appvg ...

  3. 使用PsPing测试Azure虚拟机的连通性

    Azure虚拟机启动后,如果在个人的PC上ping该虚拟机的public IP,会出现Request time out的信息,无法ping通.这是因为在 Azure 中,ICMP 包无法通过防火墙和负 ...

  4. linux软件管理之python包管理

    Python包管理 ====================================================================================python ...

  5. IPFS 使用入门

    在上一篇文章介绍了IPFS要做什么, 本篇文章介绍下IPFS怎么用, 按照本站的风格,我不会仅仅把一个个命令列出来,同时会说明命令在后面为我们做了什么. IPFS 安装 要使用IPFS, 第一步肯定是 ...

  6. Adobe Photoshop安装

    Photoshop cc2018安装 Adobe 软件套装已不再以 (Creative Suite) CS命名,而是改成 (Creative Cloud) CC,主推云服务!Adobe CC 套装中总 ...

  7. python - 递归 二分法

    一.一些内置函数 1.revsered  翻转,返回的是迭代器 # 将 s 倒置 s = '不是上海自来水来自海上' # 方法一 print(s[::-1]) # 方法二 s1 = reversed( ...

  8. 查看JVM内存使用状况

    1.jps:查看本地正在运行的java进程和进程ID(pid) 2.jinfo pid,查看指定pid的所有JVM信息 1)jinfo -flags pid 查询虚拟机运行参数信息. 2)jinfo ...

  9. caioj.cn 3004:中山市第九届小学生信息学邀请赛试题 5.合并线段

    CSDN的博客 友键 [题目描述] 有一条很长的尺子,上面标记着整数点的坐标.如: 现在给出n条线段,每条线段表示为x-y(x和y为整数,x<=y),两条线段能合并的条件是x-y,y-z,合并为 ...

  10. 实现我的第一个Java程序

    第一步.打开记事本 第二步.代码编写 public class Hello{ public static void main( String[] args){ System.out.println(& ...