ORM框架

介绍:

ORM(Object Relational Mapping),并且存放在专门 的对象一映射文件中。简单理解为一种框架的格式 数据库特点:数据库而言,只认识Sql语句 就是用来操作数据库,不用像之前使用Sql语句去操作 数据库了,关注实体对象。

每个对象----数据库中的每 个表, 不用关注Sql语句;

以对象为核心(OOP),操作对象---完成对于数据库的 操作。

OOP---完成对于数据库的操作。---统一了编程思想;

ORM框架--访问操作数据库

把数据的操作命令交给ORM框架,ORM框架把操作落实到数据 库中去;---ORM的操作当然是OOP面向对象编程;

  1. 面向对象的思想---操作数据库【伟大的思想】
  2. 足够便捷----上手简单—(数据库而言—数据库只认识Sql语句)

底层实现必然还是要转换成Sql语句—数据库只认识Sql语句;

常见的ORM

  1. EFCore
  2. EF
  3. Dos.ORM
  4. SqlSugar
  5. 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容器

  1. 注册抽象和具体之间的关系
  2. 构造函数注入
  3. 支持更多配置

在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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值