diff --git a/BaseEntity.md b/BaseEntity.md index ac9fa3d..ee44ffe 100644 --- a/BaseEntity.md +++ b/BaseEntity.md @@ -1,16 +1,85 @@ -BaseEntity 是一种极简单的 CodeFirst 开发方式,特别对单表操作时,利用重载节省了每个实体类的重复属性(创建时间、ID等字段),软件删除等功能,进行 crud 操作时不必时常考虑仓储的使用; +# 前言 -## 使用 +尝试过 ado.net、dapper、ef,以及Repository仓储,甚至自己还写过生成器工具,以便做常规CRUD操作。 + +它们日常操作不方便之处: + +- 每次使用前需要声明,再操作; + +- 很多人一个实体类,对应一个操作类(或DAL、DbContext、Repository); + +本文介绍 BaseEntity 一种极简约的 CRUD 操作方法。 + +# 功能特点 + +- 自动迁移实体结构(CodeFirst),到数据库; + +- 直接操作实体的方法,进行 CRUD 操作; + +- 简化用户定义实体类型,省去主键、常用字段的配置(如CreateTime、UpdateTime); + +- 实现单表、多表查询的软删除逻辑; + +# 声明 + +参考 BaseEntity.cs 源码(约100行),copy 到项目中使用,然后添加 nuget 引用包: + +> dotnet add package FreeSql.Repository + +> dotnet add package FreeSql.Provider.Sqlite + +1、定义一个主键 int 并且自增的实体类型,BaseEntity TKey 指定为 int/long 时,会认为主键是自增; ```csharp public class UserGroup : BaseEntity { - /// - /// 组名 - /// public string GroupName { get; set; } } +``` +如果不想主键是自增键,可以重写属性: + +```csharp +public class UserGroup : BaseEntity +{ + [Column(IsIdentity = false)] + public override int Id { get; set; } + public string GroupName { get; set; } +} +``` +> 有关更多实体的特性配置,请参考资料:https://github.com/2881099/FreeSql/wiki/%e5%ae%9e%e4%bd%93%e7%89%b9%e6%80%a7 + +2、定义一个主键 Guid 的实体类型,保存数据时会自动产生有序不重复的 Guid 值(不用自己指定 Guid.NewGuid()); + +```csharp +public class User : BaseEntity +{ + public string UserName { get; set; } +} +``` + +3、定义多主键的实体类型,可以在 static 构造函数中重写字段名; + +```csharp +public class User2 : BaseEntity +{ + static User2() + { + User2.Orm.CodeFirst.ConfigEntity(t => + { + t.Property(a => a.PkId1).Name("UserId"); + t.Property(a => a.PkId2).Name("Index"); + }); + } + + public string Username { get; set; } +} +``` + + +# CRUD 使用 + +```csharp //添加 var item = new UserGroup { GroupName = "组一" }; item.Insert(); @@ -30,228 +99,15 @@ item.Restore(); //根据主键获取对象 var item = UserGroup.Find(1); + +//查询数据 +var items = UserGroup.Where(a => a.Id > 10).ToList(); ``` -## 约定 +实体类型.Select 是一个查询对象,使用方法和 FreeSql.ISelect 一样; -- 当 BaseEntity TKey 指定为 int/long 时,会认为主键是自增; +支持多表查询时,软删除条件会附加在每个表中; -- BaseEntity 的属性或方法可以在继承类中重写,如 int Id 重写自增设置 [Column(IsIdentity = false)] ; +> 有关更多查询方法,请参考资料:https://github.com/2881099/FreeSql/wiki/%e6%9f%a5%e8%af%a2 -- IFreeSql ORM 对象在 BaseEntity 中定义,暂时不考虑多库操作; - -- 多表查询时,软删除条件会附加在每个表中; - -- 多主键的实体,在 static 构造函数中重写字段名,如: - -```csharp -public class User2 : BaseEntity -{ - static User2() - { - User2.Orm.CodeFirst.ConfigEntity(t => - { - t.Property(a => a.PkId1).Name("UserId"); - t.Property(a => a.PkId2).Name("Index"); - }); - } - - /// - /// 登陆名 - /// - public string Username { get; set; } - - /// - /// 昵称 - /// - public string Nickname { get; set; } - - /// - /// 头像 - /// - public string Avatar { get; set; } - - /// - /// 描述 - /// - public string Description { get; set; } -} -``` - -示范项目:https://github.com/2881099/FreeSql/tree/master/Examples/base_entity - -## BaseEntity 代码 - -> dotnet add package FreeSql.Repository - -> dotnet add package FreeSql.Provider.Sqlite - -```csharp -using FreeSql; -using FreeSql.DataAnnotations; -using Newtonsoft.Json; -using System; -using System.Diagnostics; -using System.Linq.Expressions; - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity -{ - private static Lazy _ormLazy = new Lazy(() => - { - var orm = new FreeSqlBuilder() - .UseAutoSyncStructure(true) - .UseNoneCommandParameter(true) - .UseConnectionString(DataType.Sqlite, "data source=test.db;max pool size=2") - //.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=2") - //.UseConnectionString(FreeSql.DataType.PostgreSQL, "Host=192.168.164.10;Port=5432;Username=postgres;Password=123456;Database=tedb;Pooling=true;Maximum Pool Size=2") - //.UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=freesqlTest;Pooling=true;Max Pool Size=2") - //.UseConnectionString(FreeSql.DataType.Oracle, "user id=user1;password=123456;data source=//127.0.0.1:1521/XE;Pooling=true;Max Pool Size=2") - .Build(); - orm.Aop.CurdBefore += (s, e) => Trace.WriteLine(e.Sql + "\r\n"); - return orm; - }); - public static IFreeSql Orm => _ormLazy.Value; - - /// - /// 创建时间 - /// - public DateTime CreateTime { get; set; } - /// - /// 更新时间 - /// - public DateTime UpdateTime { get; set; } - /// - /// 逻辑删除 - /// - public bool IsDeleted { get; set; } -} - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity : BaseEntity where TEntity : class -{ - public static ISelect Select => Orm.Select().WhereCascade(a => (a as BaseEntity).IsDeleted == false); - public static ISelect Where(Expression> exp) => Select.Where(exp); - public static ISelect WhereIf(bool condition, Expression> exp) => Select.WhereIf(condition, exp); - - [JsonIgnore] - protected IBaseRepository Repository { get; set; } - - bool UpdateIsDeleted(bool value) - { - if (this.Repository == null) - return Orm.Update(this as TEntity).Set(a => (a as BaseEntity).IsDeleted, this.IsDeleted = value).ExecuteAffrows() == 1; - this.IsDeleted = value; - return this.Repository.Update(this as TEntity) == 1; - } - /// - /// 删除数据 - /// - /// - public virtual bool Delete() => this.UpdateIsDeleted(true); - /// - /// 恢复删除的数据 - /// - /// - public virtual bool Restore() => this.UpdateIsDeleted(false); - - /// - /// 附加实体,在更新数据时,只更新变化的部分 - /// - public void Attach() - { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.Attach(this as TEntity); - } - /// - /// 更新数据 - /// - /// - public virtual bool Update() - { - if (this.Repository == null) - return Orm.Update().SetSource(this as TEntity).ExecuteAffrows() == 1; - return this.Repository.Update(this as TEntity) == 1; - } - /// - /// 插入数据 - /// - public virtual void Insert() - { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.Insert(this as TEntity); - } - - /// - /// 更新或插入 - /// - /// - public virtual void Save() - { - if (this.Repository == null) this.Repository = Orm.GetRepository(); - this.Repository.InsertOrUpdate(this as TEntity); - } -} - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity : BaseEntity where TEntity : class -{ - static BaseEntity() - { - var tkeyType = typeof(TKey)?.NullableTypeOrThis(); - if (tkeyType == typeof(int) || tkeyType == typeof(long)) - Orm.CodeFirst.ConfigEntity(typeof(TEntity), - t => t.Property("Id").IsIdentity(true)); - } - - /// - /// 主键 - /// - public virtual TKey Id { get; set; } - - /// - /// 根据主键值获取数据 - /// - /// - /// - public static TEntity Find(TKey id) - { - var item = Select.WhereDynamic(id).First(); - (item as BaseEntity)?.Attach(); - return item; - } -} - -[Table(DisableSyncStructure = true)] -public abstract class BaseEntity : BaseEntity where TEntity : class -{ - - /// - /// 主键1 - /// - [Column(IsPrimary = true)] - public virtual TKey1 PkId1 { get; set; } - /// - /// 主键2 - /// - [Column(IsPrimary = true)] - public virtual TKey2 PkId2 { get; set; } - - /// - /// 根据主键值获取数据 - /// - /// 主键1 - /// 主键2 - /// - public static TEntity Find(TKey1 pkid1, TKey1 pkid2) - { - var item = Select.WhereDynamic(new - { - PkId1 = pkid1, - PkId2 = pkid2 - }).First(); - (item as BaseEntity).Attach(); - return item; - } -} -``` \ No newline at end of file +示范项目:https://github.com/2881099/FreeSql/tree/master/Examples/base_entity \ No newline at end of file