介绍:
ORM(Object Relational Mapping),并且存放在专门 的对象一映射文件中。简单理解为一种框架的格式 数据库特点:数据库而言,只认识Sql语句 就是用来操作数据库,不用像之前使用Sql语句去操作 数据库了,关注实体对象。
每个对象----数据库中的每 个表, 不用关注Sql语句;
以对象为核心(OOP),操作对象---完成对于数据库的 操作。
OOP---完成对于数据库的操作。---统一了编程思想;
ORM框架--访问操作数据库
把数据的操作命令交给ORM框架,ORM框架把操作落实到数据 库中去;---ORM的操作当然是OOP面向对象编程;
- 面向对象的思想---操作数据库【伟大的思想】
- 足够便捷----上手简单—(数据库而言—数据库只认识Sql语句)
底层实现必然还是要转换成Sql语句—数据库只认识Sql语句;

常见的ORM
- EFCore
- EF
- Dos.ORM
- SqlSugar
- FreeSql
快速使用EFCore
EntityFrameworkCore 实体框架核心---微软提供的ORM---程序集来支持的~~
1.Nuget引入
核心应用程序:Microsoft.EntityFrameworkCore
数据库驱动程序:Microsoft.EntityFrameworkCore.SqlServer
帮助类库:Microsoft.EntityFrameworkCore.Tools

2.准备DbContext 实体
可以自动生成,也可以手写
自动生成命令:
Scaffold-DbContext "数据库连接字符串" Microsoft.EntityFrameworkCore.SqlServer -OutputDir {Models文件夹目录} -ContextDir {Contexts文件夹目录} -Force
我的为例:
Scaffold-DbContext "Data Source=LITTLESEAPAD;Initial Catalog=XiaoHaiStudy; Persist Security Info=True;User ID=sa;Password=abc123;Encrypt=True;Trust Server Certificate=True" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -ContextDir Contexts -Force
第一步:工具-->NuGet包管理器-->程序包管理器控制台

第二步:在下方输入命令然后回车:
注意:必须是当前启动项目,都设置正确,且运行没有报错

第三步:可以看到自动生成两个文件:Models就是此数据库中所有的实体类

DbContext内容和解析:
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using XH.AdoNetDemo.Models;
namespace XH.AdoNetDemo.Contexts;
// 用于操作数据库的核心上下文
public partial class XiaoHaiStudyDbContext : DbContext
{
public XiaoHaiStudyDbContext()
{
}
/// <summary>
/// 传递参数给父类来创建当前Context的实例配置
/// </summary>
/// <param name="options"></param>
public XiaoHaiStudyDbContext(DbContextOptions<XiaoHaiStudyDbContext> options)
: base(options)
{
}
#region 需要操作的数据库表一一对应都需要在这个里配置 必须和数据库完全高度匹配
public virtual DbSet<ScoreInfo> ScoreInfos { get; set; }
#endregion
/// <summary>
/// 补充配置操作数据库上下文DbContext的信息
/// </summary>
/// <param name="optionsBuilder"></param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
// 警告信息 可以删除
//#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.UseSqlServer("Data Source=LITTLESEAPAD;Initial Catalog=XiaoHaiStudy;Persist Security Info=True;User ID=sa;Password=abc123;Encrypt=True;Trust Server Certificate=True");
{
// 配置一个数据库连接字符串
if (!optionsBuilder.IsConfigured)
optionsBuilder.UseSqlServer("Data Source=LITTLESEAPAD;Initial Catalog=XiaoHaiStudy;Persist Security Info=True;User ID=sa;Password=abc123;Encrypt=True;Trust Server Certificate=True");
}
/// <summary>
/// 配置实体对象的映射关系
///
/// 这里需要配置的:
/// 1.主键的关联关系
/// 2.表名称的映射
/// 3.属性名称的映射关系
/// 4.主外键的关系
/// 5.默认值
/// 6.初始值。。。。
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ScoreInfo>(entity =>
{
entity
.ToTable("ScoreInfo") // 表名称
.HasKey(x => x.Id); // 配置主键
// 字段配置
entity.Property(e => e.Course)
.HasMaxLength(255)
.IsFixedLength()
.HasColumnName("course");
entity.Property(e => e.Id)
.ValueGeneratedOnAdd()
.HasColumnName("id");
entity.Property(e => e.Name)
.HasMaxLength(255)
.IsFixedLength()
.HasColumnName("name");
entity.Property(e => e.Score).HasColumnName("score");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
3.实操数据库
每次执行修改删除和新增的时候都需要执行一下 SaveChanges();
using (XiaoHaiStudyDbContext context = new XiaoHaiStudyDbContext())
{
context.Add(scoreInfo);
// 提交保存
context.SaveChanges();
// 查询
var score = context.ScoreInfos.FirstOrDefault(c => c.Name.Equals("小帅"));
// 修改
scoreInfo.Course = "数学";
context.SaveChanges();
context.Remove(scoreInfo);
context.SaveChanges();
}
项目分层架构

可以简单的分层为:

其中有很多类都需要增删改查等一系列操作,可以封装为Base接口:
public interface IBaseService
{
#region Query
/// <summary>
/// 根据id查询实体
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
T Find<T>(int id) where T : class;
/// <summary>
/// 提供对单表的查询
/// </summary>
/// <returns>IQueryable类型集合</returns>
[Obsolete("尽量避免使用,using 带表达式目录树的 代替")]
IQueryable<T> Set<T>() where T : class;
/// <summary>
/// 查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="funcWhere"></param>
/// <returns></returns>
IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class;
/// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="S"></typeparam>
/// <param name="funcWhere"></param>
/// <param name="pageSize"></param>
/// <param name="pageIndex"></param>
/// <param name="funcOrderby"></param>
/// <param name="isAsc"></param>
/// <returns></returns>
PageResult<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true) where T : class;
#endregion
#region Add
/// <summary>
/// 新增数据,即时Commit
/// </summary>
/// <param name="t"></param>
/// <returns>返回带主键的实体</returns>
T Insert<T>(T t) where T : class;
/// <summary>
/// 新增数据,即时Commit
/// 多条sql 一个连接,事务插入
/// </summary>
/// <param name="tList"></param>
IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class;
#endregion
#region Update
/// <summary>
/// 更新数据,即时Commit
/// </summary>
/// <param name="t"></param>
void Update<T>(T t) where T : class;
/// <summary>
/// 更新数据,即时Commit
/// </summary>
/// <param name="tList"></param>
void Update<T>(IEnumerable<T> tList) where T : class;
#endregion
#region Delete
/// <summary>
/// 根据主键删除数据,即时Commit
/// </summary>
/// <param name="t"></param>
void Delete<T>(int Id) where T : class;
/// <su+mary>
/// 删除数据,即时Commit
/// </summary>
/// <param name="t"></param>
void Delete<T>(T t) where T : class;
/// <summary>
/// 删除数据,即时Commit
/// </summary>
/// <param name="tList"></param>
void Delete<T>(IEnumerable<T> tList) where T : class;
#endregion
#region Other
/// <summary>
/// 立即保存全部修改
/// 把增/删的savechange给放到这里,是为了保证事务的
/// </summary>
void Commit();
/// <summary>
/// 执行sql 返回集合
/// </summary>
/// <param name="sql"></param>
/// <param name="parameters"></param>
/// <returns></returns>
IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class;
/// <summary>
/// 执行sql,无返回
/// </summary>
/// <param name="sql"></param>
/// <param name="parameters"></param>
void Excute<T>(string sql, SqlParameter[] parameters) where T : class;
#endregion
}
Base实现:
public class BaseService : IBaseService
{
// Context 数据库操作的EFCore的上下文的Context
protected readonly DbContext Context;
public BaseService(DbContext context)
{
Context = context;
}
#region Query
/// <summary>
/// Context 就是数据库操作的EFcore的上下文Context
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <returns></returns>
public T Find<T>(int id) where T : class
{
return Context.Set<T>().Find(id);
}
/// <summary>
/// 不应该暴露给上端使用者,尽量少用
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
//[Obsolete("尽量避免使用,using 带表达式目录树的代替")]
public IQueryable<T> Set<T>() where T : class
{
return Context.Set<T>();
}
/// <summary>
/// 这才是合理的做法,上端给条件,这里查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="funcWhere"></param>
/// <returns></returns>
public IQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere) where T : class
{
return Context.Set<T>().Where(funcWhere);
}
/// <summary>
/// 分页查询
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="S"></typeparam>
/// <param name="funcWhere"></param>
/// <param name="pageSize"></param>
/// <param name="pageIndex"></param>
/// <param name="funcOrderby"></param>
/// <param name="isAsc"></param>
/// <returns></returns>
public PageResult<T> QueryPage<T, S>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, S>> funcOrderby, bool isAsc = true) where T : class
{
var list = Set<T>();
if (funcWhere != null)
{
list = list.Where(funcWhere);
}
if (isAsc)
{
list = list.OrderBy(funcOrderby);
}
else
{
list = list.OrderByDescending(funcOrderby);
}
PageResult<T> result = new PageResult<T>()
{
DataList = list.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(),
PageIndex = pageIndex,
PageSize = pageSize,
TotalCount = list.Count()
};
return result;
}
#endregion
#region Insert
/// <summary>
/// 即使保存 不需要再Commit
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public T Insert<T>(T t) where T : class
{
Context.Set<T>().Add(t);
Commit();//写在这里 就不需要单独commit 不写就需要
return t;
}
public IEnumerable<T> Insert<T>(IEnumerable<T> tList) where T : class
{
Context.Set<T>().AddRange(tList);
Commit();//一个链接 多个sql
return tList;
}
#endregion
#region Update
/// <summary>
/// 是没有实现查询,直接更新的,需要Attach和State
///
/// 如果是已经在context,只能再封装一个(在具体的service)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public void Update<T>(T t) where T : class
{
if (t == null) throw new Exception("t is null");
Context.Set<T>().Attach(t);//将数据附加到上下文,支持实体修改和新实体,重置为UnChanged
Context.Entry(t).State = EntityState.Modified;
Commit();//保存 然后重置为UnChanged
}
public void Update<T>(IEnumerable<T> tList) where T : class
{
foreach (var t in tList)
{
Context.Set<T>().Attach(t);
Context.Entry(t).State = EntityState.Modified;
}
Commit();
}
#endregion
#region Delete
/// <summary>
/// 先附加 再删除
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
public void Delete<T>(T t) where T : class
{
if (t == null) throw new Exception("t is null");
Context.Set<T>().Attach(t);
Context.Set<T>().Remove(t);
Commit();
}
/// <summary>
/// 还可以增加非即时commit版本的,
/// 做成protected
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="Id"></param>
public void Delete<T>(int Id) where T : class
{
T t = Find<T>(Id);//也可以附加
if (t == null) throw new Exception("t is null");
Context.Set<T>().Remove(t);
Commit();
}
public void Delete<T>(IEnumerable<T> tList) where T : class
{
foreach (var t in tList)
{
Context.Set<T>().Attach(t);
}
Context.Set<T>().RemoveRange(tList);
Commit();
}
#endregion
#region Other
/// <summary>
/// 本省就是一个事务,前面可以多个操作,这里的SaveChange 就是把多个操作统一提交
/// </summary>
public void Commit()
{
Context.SaveChanges();
}
public IQueryable<T> ExcuteQuery<T>(string sql, SqlParameter[] parameters) where T : class
{
return null;
}
public void Excute<T>(string sql, SqlParameter[] parameters) where T : class
{
IDbContextTransaction trans = null;
//DbContextTransaction trans = null;
try
{
trans = Context.Database.BeginTransaction(); //这里是启动一个事务
//this.Context.Database.ExecuteSqlRaw(sql, parameters);
trans.Commit();
}
catch (Exception)
{
if (trans != null)
trans.Rollback();
throw;
}
}
public virtual void Dispose()
{
if (Context != null)
{
Context.Dispose();
}
}
#endregion
}
然在每个业务逻辑的Service中写自己的业务逻辑:然后每个实现类都继承Base,就可以实现增删改查操作:
例如:

整合IOC容器
- 注册抽象和具体之间的关系
- 构造函数注入
- 支持更多配置

在IOC中使用EFCore:
public ViewModelLocator()
{
// 注册
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<MainWindowViewModel>();
// 注入刚才写的接口和实现类
builder.RegisterType<ScoreInfoService>().As<IScoreInfoService>();
container = builder.Build();
}
使用:
private readonly IScoreInfoService _scoreInfoService;
public MainWindowViewModel(IScoreInfoService scoreInfoService)
{
_scoreInfoService = scoreInfoService;
InitScoreList();
}
private void InitScoreList()
{
List<ScoreInfo> scoreList = new List<ScoreInfo>();
// 直接查询即可
// 可以使用Base中的所有方法
scoreList= _scoreInfoService.Set<ScoreInfo>().ToList();
foreach (ScoreInfo item in scoreList)
{
ScoreList.Add(item);
}
}
2374

被折叠的 条评论
为什么被折叠?



