diff --git a/FreeSql.Repository/DataFilter.cs b/FreeSql.Repository/DataFilter.cs deleted file mode 100644 index 63c435b0..00000000 --- a/FreeSql.Repository/DataFilter.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Linq.Expressions; -using System.Text; -using System.Linq; - -namespace FreeSql { - public interface IDataFilter : IDisposable where TEntity : class { - - IDataFilter Apply(string filterName, Expression> filterAndValidateExp); - - /// - /// 开启过滤器,若使用 using 则使用完后,恢复为原有状态 - /// - /// 过滤器名称 - /// - IDisposable Enable(params string[] filterName); - /// - /// 开启所有过滤器,若使用 using 则使用完后,恢复为原有状态 - /// - /// - IDisposable EnableAll(); - - /// - /// 禁用过滤器,若使用 using 则使用完后,恢复为原有状态 - /// - /// - /// - IDisposable Disable(params string[] filterName); - /// - /// 禁用所有过滤器,若使用 using 则使用完后,恢复为原有状态 - /// - /// - IDisposable DisableAll(); - - bool IsEnabled(string filterName); - } - - internal class DataFilter : IDataFilter where TEntity : class { - - internal class FilterItem { - public Expression> Expression { get; set; } - Func _expressionDelegate; - public Func ExpressionDelegate => _expressionDelegate ?? (_expressionDelegate = Expression?.Compile()); - public bool IsEnabled { get; set; } - } - - internal ConcurrentDictionary _filters = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase); - public IDataFilter Apply(string filterName, Expression> filterAndValidateExp) { - - if (filterName == null) - throw new ArgumentNullException(nameof(filterName)); - if (filterAndValidateExp == null) return this; - - var filterItem = new FilterItem { Expression = filterAndValidateExp, IsEnabled = true }; - _filters.AddOrUpdate(filterName, filterItem, (k, v) => filterItem); - return this; - } - - public IDisposable Disable(params string[] filterName) { - if (filterName == null || filterName.Any() == false) return new UsingAny(() => { }); - - List restore = new List(); - foreach (var name in filterName) { - if (_filters.TryGetValue(name, out var tryfi)) { - if (tryfi.IsEnabled) { - restore.Add(name); - tryfi.IsEnabled = false; - } - } - } - return new UsingAny(() => this.Enable(restore.ToArray())); - } - public IDisposable DisableAll() { - List restore = new List(); - foreach (var val in _filters) { - if (val.Value.IsEnabled) { - restore.Add(val.Key); - val.Value.IsEnabled = false; - } - } - return new UsingAny(() => this.Enable(restore.ToArray())); - } - class UsingAny : IDisposable { - Action _ondis; - public UsingAny(Action ondis) { - _ondis = ondis; - } - public void Dispose() { - _ondis?.Invoke(); - } - } - - public IDisposable Enable(params string[] filterName) { - if (filterName == null || filterName.Any() == false) return new UsingAny(() => { }); - - List restore = new List(); - foreach (var name in filterName) { - if (_filters.TryGetValue(name, out var tryfi)) { - if (tryfi.IsEnabled == false) { - restore.Add(name); - tryfi.IsEnabled = true; - } - } - } - return new UsingAny(() => this.Disable(restore.ToArray())); - } - public IDisposable EnableAll() { - List restore = new List(); - foreach (var val in _filters) { - if (val.Value.IsEnabled == false) { - restore.Add(val.Key); - val.Value.IsEnabled = true; - } - } - return new UsingAny(() => this.Disable(restore.ToArray())); - } - - public bool IsEnabled(string filterName) { - if (filterName == null) return false; - return _filters.TryGetValue(filterName, out var tryfi) ? tryfi.IsEnabled : false; - } - - ~DataFilter() { - this.Dispose(); - } - public void Dispose() { - _filters.Clear(); - } - } - - public class FluentDataFilter : IDisposable { - - internal List<(Type type, string name, LambdaExpression exp)> _filters = new List<(Type type, string name, LambdaExpression exp)>(); - - public FluentDataFilter Apply(string filterName, Expression> filterAndValidateExp) where TEntity : class { - if (filterName == null) - throw new ArgumentNullException(nameof(filterName)); - if (filterAndValidateExp == null) return this; - - _filters.Add((typeof(TEntity), filterName, filterAndValidateExp)); - return this; - } - - ~FluentDataFilter() { - this.Dispose(); - } - public void Dispose() { - _filters.Clear(); - } - } -} diff --git a/FreeSql.Repository/DataFilterUtil.cs b/FreeSql.Repository/DataFilterUtil.cs deleted file mode 100644 index 77f41a5d..00000000 --- a/FreeSql.Repository/DataFilterUtil.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; - -namespace FreeSql { - - internal class DataFilterUtil { - - internal static Action _globalDataFilter; - - static ConcurrentDictionary _dicSetRepositoryDataFilterApplyDataFilterFunc = new ConcurrentDictionary(); - static ConcurrentDictionary> _dicSetRepositoryDataFilterConvertFilterNotExists = new ConcurrentDictionary>(); - internal static void SetRepositoryDataFilter(object repos, Action scopedDataFilter) { - if (scopedDataFilter != null) { - SetRepositoryDataFilter(repos, null); - } - if (scopedDataFilter == null) { - scopedDataFilter = _globalDataFilter; - } - if (scopedDataFilter == null) return; - using (var globalFilter = new FluentDataFilter()) { - scopedDataFilter(globalFilter); - - var type = repos.GetType(); - Type entityType = (repos as IRepository).EntityType; - if (entityType == null) throw new Exception("FreeSql.Repository 设置过滤器失败,原因是对象不属于 IRepository"); - - var notExists = _dicSetRepositoryDataFilterConvertFilterNotExists.GetOrAdd(type, t => new ConcurrentDictionary()); - var newFilter = new Dictionary(); - foreach (var gf in globalFilter._filters) { - if (notExists.ContainsKey(gf.name)) continue; - - LambdaExpression newExp = null; - var filterParameter1 = Expression.Parameter(entityType, gf.exp.Parameters[0].Name); - try { - newExp = Expression.Lambda( - typeof(Func<,>).MakeGenericType(entityType, typeof(bool)), - new ReplaceVisitor().Modify(gf.exp.Body, filterParameter1), - filterParameter1 - ); - } catch { - notExists.TryAdd(gf.name, true); //防止第二次错误 - continue; - } - newFilter.Add(gf.name, newExp); - } - if (newFilter.Any() == false) return; - - var del = _dicSetRepositoryDataFilterApplyDataFilterFunc.GetOrAdd(type, t => { - var reposParameter = Expression.Parameter(type); - var nameParameter = Expression.Parameter(typeof(string)); - var expressionParameter = Expression.Parameter( - typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(entityType, typeof(bool))) - ); - return Expression.Lambda( - Expression.Block( - Expression.Call(reposParameter, type.GetMethod("ApplyDataFilter", BindingFlags.Instance | BindingFlags.NonPublic), nameParameter, expressionParameter) - ), - new[] { - reposParameter, nameParameter, expressionParameter - } - ).Compile(); - }); - foreach (var nf in newFilter) { - del.DynamicInvoke(repos, nf.Key, nf.Value); - } - newFilter.Clear(); - } - } - } - - class ReplaceVisitor : ExpressionVisitor { - private ParameterExpression parameter; - - public Expression Modify(Expression expression, ParameterExpression parameter) { - this.parameter = parameter; - return Visit(expression); - } - - protected override Expression VisitMember(MemberExpression node) { - if (node.Expression?.NodeType == ExpressionType.Parameter) - return Expression.Property(parameter, node.Member.Name); - return base.VisitMember(node); - } - } -} diff --git a/FreeSql.Repository/Extenssions/AutofacDependencyInjection.cs b/FreeSql.Repository/Extenssions/AutofacDependencyInjection.cs deleted file mode 100644 index 038a09a8..00000000 --- a/FreeSql.Repository/Extenssions/AutofacDependencyInjection.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Autofac; -using FreeSql; -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Linq.Expressions; -using System.Reflection; -using System.Linq; - -public static class FreeSqlRepositoryAutofacExtenssions { - - /// - /// 注册 FreeSql.Repository 包括 泛型、继承实现的仓储 - /// - /// - /// 全局过滤设置 - /// 继承实现的仓储,所在的程序集 - public static void RegisterFreeRepository(this ContainerBuilder builder, Action globalDataFilter = null, params Assembly[] assemblies) => - RegisterFreeRepositoryPrivate(builder, globalDataFilter, assemblies); - - static void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Action globalDataFilter, params Assembly[] assemblies) { - - DataFilterUtil._globalDataFilter = globalDataFilter; - - builder.RegisterGeneric(typeof(GuidRepository<>)).As( - typeof(GuidRepository<>), - typeof(BaseRepository<>), - typeof(IBasicRepository<>), - typeof(IReadOnlyRepository<>) - ).OnActivating(a => { - //Utils.SetRepositoryDataFilter(a.Instance); - }).InstancePerDependency(); - - builder.RegisterGeneric(typeof(DefaultRepository<,>)).As( - typeof(DefaultRepository<,>), - typeof(BaseRepository<,>), - typeof(IBasicRepository<,>), - typeof(IReadOnlyRepository<,>) - ).OnActivating(a => { - //Utils.SetRepositoryDataFilter(a.Instance); - }).InstancePerDependency(); - - builder.RegisterAssemblyTypes(assemblies).Where(a => { - return typeof(IRepository).IsAssignableFrom(a); - }).InstancePerDependency(); - - } -} diff --git a/FreeSql.Repository/Extenssions/DependencyInjection.cs b/FreeSql.Repository/Extenssions/DependencyInjection.cs deleted file mode 100644 index e258b676..00000000 --- a/FreeSql.Repository/Extenssions/DependencyInjection.cs +++ /dev/null @@ -1,39 +0,0 @@ -using FreeSql; -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Linq.Expressions; -using System.Reflection; -using System.Linq; -using Microsoft.Extensions.DependencyInjection; - -namespace FreeSql { - public static class FreeSqlRepositoryDependencyInjection { - - public static IServiceCollection AddFreeRepository(this IServiceCollection services, Action globalDataFilter = null, params Assembly[] assemblies) { - - DataFilterUtil._globalDataFilter = globalDataFilter; - - services.AddScoped(typeof(IReadOnlyRepository<>), typeof(GuidRepository<>)); - services.AddScoped(typeof(IBasicRepository<>), typeof(GuidRepository<>)); - services.AddScoped(typeof(BaseRepository<>), typeof(GuidRepository<>)); - services.AddScoped(typeof(GuidRepository<>)); - - services.AddScoped(typeof(IReadOnlyRepository<,>), typeof(DefaultRepository<,>)); - services.AddScoped(typeof(IBasicRepository<,>), typeof(DefaultRepository<,>)); - services.AddScoped(typeof(BaseRepository<,>), typeof(DefaultRepository<,>)); - services.AddScoped(typeof(DefaultRepository<,>)); - - if (assemblies?.Any() == true) { - foreach(var asse in assemblies) { - foreach (var repos in asse.GetTypes().Where(a => a.IsAbstract == false && typeof(IRepository).IsAssignableFrom(a))) { - - services.AddScoped(repos); - } - } - } - - return services; - } - } -} \ No newline at end of file diff --git a/FreeSql.Repository/Extenssions/FreeSqlRepositoryExtenssions.cs b/FreeSql.Repository/Extenssions/FreeSqlRepositoryExtenssions.cs deleted file mode 100644 index ab5fcccd..00000000 --- a/FreeSql.Repository/Extenssions/FreeSqlRepositoryExtenssions.cs +++ /dev/null @@ -1,58 +0,0 @@ -using FreeSql; -using System; -using System.Collections.Generic; -using System.Collections.Concurrent; -using System.Text; -using System.Linq.Expressions; -using System.Linq; -using System.Data; - -public static class FreeSqlRepositoryExtenssions { - - /// - /// 返回默认仓库类 - /// - /// - /// - /// - /// 数据过滤 + 验证 - /// - public static DefaultRepository GetRepository(this IFreeSql that, Expression> filter = null) where TEntity : class { - return new DefaultRepository(that, filter); - } - - /// - /// 返回仓库类,适用 Insert 方法无须返回插入的数据 - /// - /// - /// - /// 数据过滤 + 验证 - /// 分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository - /// - public static GuidRepository GetGuidRepository(this IFreeSql that, Expression> filter = null, Func asTable = null) where TEntity : class { - return new GuidRepository(that, filter, asTable); - } - - /// - /// 合并两个仓储的设置(过滤+分表),以便查询 - /// - /// - /// - /// - /// - /// - public static ISelect FromRepository(this ISelect that, BaseRepository repos) where TEntity : class where T2 : class { - var filters = (repos.DataFilter as DataFilter)._filters.Where(a => a.Value.IsEnabled == true); - foreach (var filter in filters) that.Where(filter.Value.Expression); - return that.AsTable(repos.AsTableSelectInternal); - } - - /// - /// 创建一个新的工作单元,务必使用 using 包含使用 - /// - /// - /// - public static IUnitOfWork CreateUnitOfWork(this IFreeSql that) { - return new UnitOfWork(that); - } -} \ No newline at end of file diff --git a/FreeSql.Repository/FreeSql.Repository.csproj b/FreeSql.Repository/FreeSql.Repository.csproj index a94d8ca7..77078e8b 100644 --- a/FreeSql.Repository/FreeSql.Repository.csproj +++ b/FreeSql.Repository/FreeSql.Repository.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.4.10 + 0.4.11 YeXiangQin FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table. https://github.com/2881099/FreeSql/wiki/Repository @@ -11,11 +11,7 @@ - - - - - + diff --git a/FreeSql.Repository/Repository/BaseRepository.cs b/FreeSql.Repository/Repository/BaseRepository.cs deleted file mode 100644 index 813dfa8a..00000000 --- a/FreeSql.Repository/Repository/BaseRepository.cs +++ /dev/null @@ -1,290 +0,0 @@ -using FreeSql.Extensions.EntityUtil; -using FreeSql.Internal.Model; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace FreeSql { - public abstract class BaseRepository : IRepository - where TEntity : class { - - protected IFreeSql _fsql; - internal UnitOfWork _unitOfWork; - public IDataFilter DataFilter { get; } = new DataFilter(); - - Func _asTableVal; - protected Func AsTable { - get => _asTableVal; - set { - _asTableVal = value; - AsTableSelect = value == null ? null : new Func((a, b) => a == EntityType ? value(b) : null); - } - } - protected Func AsTableSelect { get; private set; } - internal Func AsTableSelectInternal => AsTableSelect; - - public Type EntityType { get; } = typeof(TEntity); - - protected BaseRepository(IFreeSql fsql, Expression> filter, Func asTable = null) : base() { - _fsql = fsql ?? throw new NullReferenceException(nameof(fsql)); - DataFilterUtil.SetRepositoryDataFilter(this, null); - DataFilter.Apply("", filter); - AsTable = asTable; - } - - public ISelect Select => OrmSelect(null); - public IUpdate UpdateDiy => OrmUpdate(null); - - public int Delete(Expression> predicate) => OrmDelete(null).Where(predicate).ExecuteAffrows(); - public int Delete(TEntity entity) => OrmDelete(entity).ExecuteAffrows(); - public Task DeleteAsync(Expression> predicate) => OrmDelete(null).Where(predicate).ExecuteAffrowsAsync(); - public Task DeleteAsync(TEntity entity) => OrmDelete(entity).ExecuteAffrowsAsync(); - - public virtual TEntity Insert(TEntity entity) { - Add(entity); - return entity; - } - public virtual List Insert(IEnumerable entitys) { - AddRange(entitys); - return entitys.ToList(); - } - async public virtual Task InsertAsync(TEntity entity) { - await AddAsync(entity); - return entity; - } - async public virtual Task> InsertAsync(IEnumerable entitys) { - await AddRangeAsync(entitys); - return entitys.ToList(); - } - - public int Update(TEntity entity) => OrmUpdate(entity).ExecuteAffrows(); - public Task UpdateAsync(TEntity entity) => OrmUpdate(entity).ExecuteAffrowsAsync(); - - protected ISelect OrmSelect(object dywhere) { - var select = _fsql.Select(dywhere).WithTransaction(_unitOfWork?.GetOrBeginTransaction(false)); - var filters = (DataFilter as DataFilter)._filters.Where(a => a.Value.IsEnabled == true); - foreach (var filter in filters) select.Where(filter.Value.Expression); - return select.AsTable(AsTableSelect); - } - protected IUpdate OrmUpdate(object dywhere) { - var entityObj = dywhere as TEntity; - var update = _fsql.Update(dywhere).WithTransaction(_unitOfWork?.GetOrBeginTransaction()); - var filters = (DataFilter as DataFilter)._filters.Where(a => a.Value.IsEnabled == true); - foreach (var filter in filters) { - if (entityObj != null && filter.Value.ExpressionDelegate?.Invoke(entityObj) == false) - throw new Exception($"FreeSql.Repository Update 失败,因为设置了 {filter.Key}: {filter.Value.Expression},更新的数据不符合"); - update.Where(filter.Value.Expression); - } - return update.AsTable(AsTable); - } - protected IDelete OrmDelete(object dywhere) { - var delete = _fsql.Delete(dywhere).WithTransaction(_unitOfWork?.GetOrBeginTransaction()); - var filters = (DataFilter as DataFilter)._filters.Where(a => a.Value.IsEnabled == true); - foreach (var filter in filters) delete.Where(filter.Value.Expression); - return delete.AsTable(AsTable); - } - protected IInsert OrmInsert(TEntity entity) => OrmInsert(new[] { entity }); - protected IInsert OrmInsert(IEnumerable entitys) { - var insert = _fsql.Insert(entitys).WithTransaction(_unitOfWork?.GetOrBeginTransaction()); - var filters = (DataFilter as DataFilter)._filters.Where(a => a.Value.IsEnabled == true); - foreach (var filter in filters) { - foreach (var entity in entitys) - if (entity != null && filter.Value.ExpressionDelegate?.Invoke(entity) == false) - throw new Exception($"FreeSql.Repository Insert 失败,因为设置了 {filter.Key}: {filter.Value.Expression},插入的数据不符合"); - } - return insert.AsTable(AsTable); - } - - protected void ApplyDataFilter(string name, Expression> exp) => DataFilter.Apply(name, exp); - - #region 参考 FreeSql.DbContext/dbset - - TableInfo _tablePriv; - TableInfo _table => _tablePriv ?? (_tablePriv = _fsql.CodeFirst.GetTableByEntity(EntityType)); - ColumnInfo[] _tableIdentitysPriv; - ColumnInfo[] _tableIdentitys => _tableIdentitysPriv ?? (_tableIdentitysPriv = _table.Primarys.Where(a => a.Attribute.IsIdentity).ToArray()); - - bool CanAdd(TEntity[] data, bool isThrow) { - if (data == null) { - if (isThrow) throw new ArgumentNullException(nameof(data)); - return false; - } - foreach (var s in data) if (CanAdd(s, isThrow) == false) return false; - return true; - } - bool CanAdd(IEnumerable data, bool isThrow) { - if (data == null) { - if (isThrow) throw new ArgumentNullException(nameof(data)); - return false; - } - foreach (var s in data) if (CanAdd(s, isThrow) == false) return false; - return true; - } - bool CanAdd(TEntity data, bool isThrow) { - if (data == null) { - if (isThrow) throw new ArgumentNullException(nameof(data)); - return false; - } - var key = _fsql.GetEntityKeyString(data); - if (string.IsNullOrEmpty(key)) { - switch (_fsql.Ado.DataType) { - case DataType.SqlServer: - case DataType.PostgreSQL: - return true; - case DataType.MySql: - case DataType.Oracle: - case DataType.Sqlite: - if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) { - return true; - } - if (isThrow) throw new Exception($"不可添加,未设置主键的值:{_fsql.GetEntityString(data)}"); - return false; - } - } else { - var idval = _fsql.GetEntityIdentityValueWithPrimary(data); - if (idval > 0) { - if (isThrow) throw new Exception($"不可添加,自增属性有值:{_fsql.GetEntityString(data)}"); - return false; - } - } - return true; - } - - void AddPriv(TEntity data, bool isCheck) { - if (isCheck && CanAdd(data, true) == false) return; - if (_tableIdentitys.Length > 0) { - //有自增,马上执行 - switch (_fsql.Ado.DataType) { - case DataType.SqlServer: - case DataType.PostgreSQL: - if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) { - var idtval = this.OrmInsert(data).ExecuteIdentity(); - _fsql.SetEntityIdentityValueWithPrimary(data, idtval); - } else { - var newval = this.OrmInsert(data).ExecuteInserted().First(); - _fsql.MapEntityValue(newval, data); - } - return; - case DataType.MySql: - case DataType.Oracle: - case DataType.Sqlite: - if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) { - var idtval = this.OrmInsert(data).ExecuteIdentity(); - _fsql.SetEntityIdentityValueWithPrimary(data, idtval); - } - return; - } - } else { - this.OrmInsert(data).ExecuteAffrows(); - } - } - public void Add(TEntity source) => AddPriv(source, true); - public void AddRange(TEntity[] data) => AddRange(data.ToList()); - public void AddRange(IEnumerable data) { - if (CanAdd(data, true) == false) return; - if (data.ElementAtOrDefault(1) == default(TEntity)) { - Add(data.First()); - return; - } - if (_tableIdentitys.Length > 0) { - //有自增,马上执行 - switch (_fsql.Ado.DataType) { - case DataType.SqlServer: - case DataType.PostgreSQL: - var rets = this.OrmInsert(data).ExecuteInserted(); - if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_fsql.Ado.DataType} 的返回数据,与添加的数目不匹配"); - var idx = 0; - foreach (var s in data) - _fsql.MapEntityValue(rets[idx++], s); - return; - case DataType.MySql: - case DataType.Oracle: - case DataType.Sqlite: - foreach (var s in data) - AddPriv(s, false); - return; - } - } else { - this.OrmInsert(data).ExecuteAffrows(); - } - } - - async Task AddPrivAsync(TEntity data, bool isCheck) { - if (isCheck && CanAdd(data, true) == false) return; - if (_tableIdentitys.Length > 0) { - //有自增,马上执行 - switch (_fsql.Ado.DataType) { - case DataType.SqlServer: - case DataType.PostgreSQL: - if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) { - var idtval = await this.OrmInsert(data).ExecuteIdentityAsync(); - _fsql.SetEntityIdentityValueWithPrimary(data, idtval); - } else { - var newval = (await this.OrmInsert(data).ExecuteInsertedAsync()).First(); - _fsql.MapEntityValue(newval, data); - } - return; - case DataType.MySql: - case DataType.Oracle: - case DataType.Sqlite: - if (_tableIdentitys.Length == 1 && _table.Primarys.Length == 1) { - var idtval = await this.OrmInsert(data).ExecuteIdentityAsync(); - _fsql.SetEntityIdentityValueWithPrimary(data, idtval); - } - return; - } - } else { - await this.OrmInsert(data).ExecuteAffrowsAsync(); - } - } - public Task AddAsync(TEntity source) => AddPrivAsync(source, true); - public Task AddRangeAsync(TEntity[] data) => AddRangeAsync(data.ToList()); - async public Task AddRangeAsync(IEnumerable data) { - if (CanAdd(data, true) == false) return; - if (data.ElementAtOrDefault(1) == default(TEntity)) { - Add(data.First()); - return; - } - if (_tableIdentitys.Length > 0) { - //有自增,马上执行 - switch (_fsql.Ado.DataType) { - case DataType.SqlServer: - case DataType.PostgreSQL: - var rets = await this.OrmInsert(data).ExecuteInsertedAsync(); - if (rets.Count != data.Count()) throw new Exception($"特别错误:批量添加失败,{_fsql.Ado.DataType} 的返回数据,与添加的数目不匹配"); - var idx = 0; - foreach (var s in data) - _fsql.MapEntityValue(rets[idx++], s); - return; - case DataType.MySql: - case DataType.Oracle: - case DataType.Sqlite: - foreach (var s in data) - await AddPrivAsync(s, false); - return; - } - } else { - await this.OrmInsert(data).ExecuteAffrowsAsync(); - } - } - #endregion - } - - public abstract class BaseRepository : BaseRepository, IRepository - where TEntity : class { - - public BaseRepository(IFreeSql fsql, Expression> filter, Func asTable = null) : base(fsql, filter, asTable) { - } - - public int Delete(TKey id) => OrmDelete(id).ExecuteAffrows(); - public Task DeleteAsync(TKey id) => OrmDelete(id).ExecuteAffrowsAsync(); - - public TEntity Find(TKey id) => OrmSelect(id).ToOne(); - public Task FindAsync(TKey id) => OrmSelect(id).ToOneAsync(); - - public TEntity Get(TKey id) => Find(id); - public Task GetAsync(TKey id) => FindAsync(id); - } -} diff --git a/FreeSql.Repository/Repository/DefaultRepository.cs b/FreeSql.Repository/Repository/DefaultRepository.cs deleted file mode 100644 index 3079b308..00000000 --- a/FreeSql.Repository/Repository/DefaultRepository.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; - -namespace FreeSql { - public class DefaultRepository : - BaseRepository - where TEntity : class { - - public DefaultRepository(IFreeSql fsql) : base(fsql, null, null) { - - } - - public DefaultRepository(IFreeSql fsql, Expression> filter) : base(fsql, filter, null) { - } - } -} diff --git a/FreeSql.Repository/Repository/GuidRepository.cs b/FreeSql.Repository/Repository/GuidRepository.cs deleted file mode 100644 index cce6ba7f..00000000 --- a/FreeSql.Repository/Repository/GuidRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; - -namespace FreeSql { - public class GuidRepository : - BaseRepository - where TEntity : class { - - public GuidRepository(IFreeSql fsql) : this(fsql, null, null) { - - } - public GuidRepository(IFreeSql fsql, Expression> filter, Func asTable) : base(fsql, filter, asTable) { - } - - public override List Insert(IEnumerable entity) { - OrmInsert(entity).ExecuteAffrows(); - return entity.ToList(); - } - async public override Task> InsertAsync(IEnumerable entity) { - await OrmInsert(entity).ExecuteAffrowsAsync(); - return entity.ToList(); - } - - public override TEntity Insert(TEntity entity) { - OrmInsert(entity).ExecuteAffrows(); - return entity; - } - async public override Task InsertAsync(TEntity entity) { - await OrmInsert(entity).ExecuteAffrowsAsync(); - return entity; - } - } -} diff --git a/FreeSql.Repository/Repository/IBasicRepository.cs b/FreeSql.Repository/Repository/IBasicRepository.cs deleted file mode 100644 index a86404c0..00000000 --- a/FreeSql.Repository/Repository/IBasicRepository.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace FreeSql { - public interface IBasicRepository : IReadOnlyRepository - where TEntity : class { - TEntity Insert(TEntity entity); - - List Insert(IEnumerable entitys); - - Task InsertAsync(TEntity entity); - - Task> InsertAsync(IEnumerable entitys); - - int Update(TEntity entity); - - Task UpdateAsync(TEntity entity); - - IUpdate UpdateDiy { get; } - - int Delete(TEntity entity); - - Task DeleteAsync(TEntity entity); - } - - public interface IBasicRepository : IBasicRepository, IReadOnlyRepository - where TEntity : class { - int Delete(TKey id); - - Task DeleteAsync(TKey id); - } -} - diff --git a/FreeSql.Repository/Repository/IReadOnlyRepository.cs b/FreeSql.Repository/Repository/IReadOnlyRepository.cs deleted file mode 100644 index 8ab03c03..00000000 --- a/FreeSql.Repository/Repository/IReadOnlyRepository.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading.Tasks; - -namespace FreeSql { - public interface IReadOnlyRepository : IRepository - where TEntity : class { - - IDataFilter DataFilter { get; } - - ISelect Select { get; } - } - - public interface IReadOnlyRepository : IReadOnlyRepository - where TEntity : class { - TEntity Get(TKey id); - - Task GetAsync(TKey id); - - TEntity Find(TKey id); - - Task FindAsync(TKey id); - } -} diff --git a/FreeSql.Repository/Repository/IRepository.cs b/FreeSql.Repository/Repository/IRepository.cs deleted file mode 100644 index d81c2080..00000000 --- a/FreeSql.Repository/Repository/IRepository.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Linq.Expressions; -using System.Threading.Tasks; - -namespace FreeSql { - - public interface IRepository { - Type EntityType { get; } - } - - public interface IRepository : IReadOnlyRepository, IBasicRepository - where TEntity : class { - int Delete(Expression> predicate); - - Task DeleteAsync(Expression> predicate); - } - - public interface IRepository : IRepository, IReadOnlyRepository, IBasicRepository - where TEntity : class { - } -} \ No newline at end of file diff --git a/FreeSql.Repository/UnitOfWork/IUnitOfWork.cs b/FreeSql.Repository/UnitOfWork/IUnitOfWork.cs deleted file mode 100644 index 5d8ed73a..00000000 --- a/FreeSql.Repository/UnitOfWork/IUnitOfWork.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Text; - -namespace FreeSql { - public interface IUnitOfWork : IDisposable { - - /// - /// 在工作单元内创建默认仓库类,工作单元下的仓储操作具有事务特点 - /// - /// - /// - /// 数据过滤 + 验证 - /// - DefaultRepository GetRepository(Expression> filter = null) where TEntity : class; - - /// - /// 在工作单元内创建仓库类,适用 Insert 方法无须返回插入的数据,工作单元下的仓储操作具有事务特点 - /// - /// - /// 数据过滤 + 验证 - /// 分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository - /// - GuidRepository GetGuidRepository(Expression> filter = null, Func asTable = null) where TEntity : class; - - void Commit(); - - void Rollback(); - } -} diff --git a/FreeSql.Repository/UnitOfWork/UnitOfWork.cs b/FreeSql.Repository/UnitOfWork/UnitOfWork.cs deleted file mode 100644 index b7383363..00000000 --- a/FreeSql.Repository/UnitOfWork/UnitOfWork.cs +++ /dev/null @@ -1,73 +0,0 @@ -using SafeObjectPool; -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq.Expressions; -using System.Text; - -namespace FreeSql { - class UnitOfWork : IUnitOfWork { - - IFreeSql _fsql; - Object _conn; - DbTransaction _tran; - - public UnitOfWork(IFreeSql fsql) { - _fsql = fsql; - } - - void ReturnObject() { - _fsql.Ado.MasterPool.Return(_conn); - _tran = null; - _conn = null; - } - internal DbTransaction GetOrBeginTransaction(bool isCreate = true) { - - if (_tran != null) return _tran; - if (isCreate == false) return null; - if (_conn != null) _fsql.Ado.MasterPool.Return(_conn); - - _conn = _fsql.Ado.MasterPool.Get(); - try { - _tran = _conn.Value.BeginTransaction(); - } catch { - ReturnObject(); - throw; - } - return _tran; - } - - public void Commit() { - if (_tran != null) { - try { - _tran.Commit(); - } finally { - ReturnObject(); - } - } - } - public void Rollback() { - if (_tran != null) { - try { - _tran.Rollback(); - } finally { - ReturnObject(); - } - } - } - public void Dispose() { - this.Rollback(); - } - - public DefaultRepository GetRepository(Expression> filter = null) where TEntity : class { - var repos = new DefaultRepository(_fsql, filter); - repos._unitOfWork = this; - return repos; - } - public GuidRepository GetGuidRepository(Expression> filter = null, Func asTable = null) where TEntity : class { - var repos = new GuidRepository(_fsql, filter, asTable); - repos._unitOfWork = this; - return repos; - } - } -} diff --git a/FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs b/FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs index 406ba4e9..134d6851 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlInsertTest.cs @@ -18,6 +18,13 @@ namespace FreeSql.Tests.MySql { public string Title { get; set; } public DateTime CreateTime { get; set; } } + class TestEnumInsertTb { + [Column(IsIdentity = true)] + public int id { get; set; } + public TestEnumInserTbType type { get; set; } + public DateTime time { get; set; } = new DateTime(); + } + enum TestEnumInserTbType { str1, biggit, sum211 } [Fact] public void AppendData() { @@ -35,6 +42,12 @@ namespace FreeSql.Tests.MySql { sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); Assert.Equal("INSERT INTO `tb_topic`(`Clicks`, `Title`) VALUES(?Clicks_0, ?Title_0), (?Clicks_1, ?Title_1), (?Clicks_2, ?Title_2), (?Clicks_3, ?Title_3), (?Clicks_4, ?Title_4), (?Clicks_5, ?Title_5), (?Clicks_6, ?Title_6), (?Clicks_7, ?Title_7), (?Clicks_8, ?Title_8), (?Clicks_9, ?Title_9)", sql); + + sql = g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).ToSql(); + Assert.Equal("INSERT INTO `TestEnumInsertTb`(`type`, `time`) VALUES(?type_0, ?time_0)", sql); + + sql = g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).NoneParameter().ToSql(); + Assert.Equal("INSERT INTO `TestEnumInsertTb`(`type`, `time`) VALUES('sum211', '0001-01-01 00:00:00')", sql); } [Fact] @@ -66,6 +79,9 @@ namespace FreeSql.Tests.MySql { Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows()); Assert.Equal(10, insert.AppendData(items).ExecuteAffrows()); + + Assert.Equal(1, g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).ExecuteAffrows()); + Assert.Equal(1, g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).NoneParameter().ExecuteAffrows()); } [Fact] public void ExecuteIdentity() { @@ -73,6 +89,11 @@ namespace FreeSql.Tests.MySql { for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity()); + + var id = g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).ExecuteIdentity(); + Assert.Equal(TestEnumInserTbType.sum211, g.mysql.Select< TestEnumInsertTb>().Where(a => a.id == id).First()?.type); + id = g.mysql.Insert().AppendData(new TestEnumInsertTb { type = TestEnumInserTbType.sum211 }).NoneParameter().ExecuteIdentity(); + Assert.Equal(TestEnumInserTbType.sum211, g.mysql.Select().Where(a => a.id == id).First()?.type); } [Fact] public void ExecuteInserted() { diff --git a/FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs b/FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs index 6399e4c0..f36e244c 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlUpdateTest.cs @@ -16,7 +16,14 @@ namespace FreeSql.Tests.MySql { public string Title { get; set; } public DateTime CreateTime { get; set; } } - + class TestEnumUpdateTb { + [Column(IsIdentity = true)] + public int id { get; set; } + public TestEnumUpdateTbType type { get; set; } + public DateTime time { get; set; } = new DateTime(); + } + enum TestEnumUpdateTbType { str1, biggit, sum211 } + [Fact] public void Dywhere() { Assert.Null(g.mysql.Update().ToSql()); @@ -42,11 +49,39 @@ namespace FreeSql.Tests.MySql { sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE `tb_topic` SET `CreateTime` = ?p_0 WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = g.mysql.Insert().AppendData(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ToSql().Replace("\r\n", ""); + Assert.Equal("INSERT INTO `TestEnumUpdateTb`(`type`, `time`) VALUES(?type_0, ?time_0)", sql); + var id = g.mysql.Insert().AppendData(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ExecuteIdentity(); + Assert.True(id > 0); + Assert.Equal(TestEnumUpdateTbType.sum211, g.mysql.Select().Where(a => a.id == id).First()?.type); + + sql = g.mysql.Update().SetSource(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = ?p_0, `time` = ?p_1 WHERE (`id` = 0)", sql); + g.mysql.Update().SetSource(new TestEnumUpdateTb { id = (int)id, type = TestEnumUpdateTbType.biggit }).ExecuteAffrows(); + Assert.Equal(TestEnumUpdateTbType.biggit, g.mysql.Select().Where(a => a.id == id).First()?.type); + + sql = g.mysql.Insert().NoneParameter().AppendData(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ToSql().Replace("\r\n", ""); + Assert.Equal("INSERT INTO `TestEnumUpdateTb`(`type`, `time`) VALUES('sum211', '0001-01-01 00:00:00')", sql); + id = g.mysql.Insert().NoneParameter().AppendData(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ExecuteIdentity(); + Assert.True(id > 0); + Assert.Equal(TestEnumUpdateTbType.sum211, g.mysql.Select().Where(a => a.id == id).First()?.type); + + sql = g.mysql.Update().NoneParameter().SetSource(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = 'sum211', `time` = '0001-01-01 00:00:00' WHERE (`id` = 0)", sql); + g.mysql.Update().NoneParameter().SetSource(new TestEnumUpdateTb { id = (int)id, type = TestEnumUpdateTbType.biggit }).ExecuteAffrows(); + Assert.Equal(TestEnumUpdateTbType.biggit, g.mysql.Select().Where(a => a.id == id).First()?.type); } [Fact] public void IgnoreColumns() { var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE `tb_topic` SET `Title` = ?p_0 WHERE (`Id` = 1)", sql); + + sql = g.mysql.Update().SetSource(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).IgnoreColumns(a => a.time).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = ?p_0 WHERE (`id` = 0)", sql); + + sql = g.mysql.Update().NoneParameter().SetSource(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).IgnoreColumns(a => a.time).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = 'sum211' WHERE (`id` = 0)", sql); } [Fact] public void Set() { @@ -68,11 +103,26 @@ namespace FreeSql.Tests.MySql { sql = update.Set(a => a.Id - incrv).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE `tb_topic` SET `Id` = `Id` - 10 WHERE (`Id` = 1)", sql); + + var id = g.mysql.Insert().AppendData(new TestEnumUpdateTb { type = TestEnumUpdateTbType.sum211 }).ExecuteIdentity(); + Assert.True(id > 0); + sql = g.mysql.Update().Where(a => a.id == id).Set(a => a.type, TestEnumUpdateTbType.biggit).ToSql().Replace("\r\n", ""); + Assert.Equal($"UPDATE `TestEnumUpdateTb` SET `type` = ?p_0 WHERE (`id` = {id})", sql); + g.mysql.Update().Where(a => a.id == id).Set(a => a.type, TestEnumUpdateTbType.biggit).ExecuteAffrows(); + Assert.Equal(TestEnumUpdateTbType.biggit, g.mysql.Select().Where(a => a.id == id).First()?.type); + + sql = g.mysql.Update().NoneParameter().Where(a => a.id == id).Set(a => a.type, TestEnumUpdateTbType.str1).ToSql().Replace("\r\n", ""); + Assert.Equal($"UPDATE `TestEnumUpdateTb` SET `type` = 'str1' WHERE (`id` = {id})", sql); + g.mysql.Update().NoneParameter().Where(a => a.id == id).Set(a => a.type, TestEnumUpdateTbType.str1).ExecuteAffrows(); + Assert.Equal(TestEnumUpdateTbType.str1, g.mysql.Select().Where(a => a.id == id).First()?.type); } [Fact] public void SetRaw() { var sql = update.Where(a => a.Id == 1).SetRaw("clicks = clicks + ?incrClick", new { incrClick = 1 }).ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE `tb_topic` SET clicks = clicks + ?incrClick WHERE (`Id` = 1)", sql); + + sql = g.mysql.Update().NoneParameter().Where(a => a.id == 0).SetRaw("`type` = {0}".FormatMySql(TestEnumUpdateTbType.sum211)).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = 'sum211' WHERE (`id` = 0)", sql); } [Fact] public void Where() { @@ -90,6 +140,10 @@ namespace FreeSql.Tests.MySql { for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); sql = update.Where(items).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); Assert.Equal("UPDATE `tb_topic` SET title='newtitle' WHERE (`Id` IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = g.mysql.Update().NoneParameter().Where(a => a.id == 0 && a.type == TestEnumUpdateTbType.str1) + .Set(a => a.type, TestEnumUpdateTbType.sum211).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE `TestEnumUpdateTb` SET `type` = 'sum211' WHERE (`id` = 0 AND `type` = 'str1')", sql); } [Fact] public void WhereExists() { diff --git a/FreeSql/FreeSql.csproj b/FreeSql/FreeSql.csproj index 1d69dcc2..56b6d4b0 100644 --- a/FreeSql/FreeSql.csproj +++ b/FreeSql/FreeSql.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 0.4.10 + 0.4.11 true YeXiangQin FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite. diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs index a7968e63..414d6b23 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs @@ -30,6 +30,25 @@ namespace FreeSql { /// List ToList(Expression> select); Task> ToListAsync(Expression> select); + + /// + /// 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 + /// + /// 返回类型 + /// 选择列 + /// + TReturn ToOne(Expression> select); + Task ToOneAsync(Expression> select); + + /// + /// 执行SQL查询,返回指定字段的记录的第一条记录,记录不存在时返回 TReturn 默认值 + /// + /// 返回类型 + /// 选择列 + /// + TReturn First(Expression> select); + Task FirstAsync(Expression> select); + /// /// 返回即将执行的SQL语句 /// diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index b01a94d6..1e6a9775 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -228,5 +228,13 @@ namespace FreeSql.Internal.CommonProvider { public bool Any(Expression> exp) => this.Where(exp).Any(); public Task AnyAsync(Expression> exp) => this.Where(exp).AnyAsync(); + + public TReturn ToOne(Expression> select) => this.Limit(1).ToList(select).FirstOrDefault(); + + async public Task ToOneAsync(Expression> select) => (await this.Limit(1).ToListAsync(select)).FirstOrDefault(); + + public TReturn First(Expression> select) => this.ToOne(select); + + public Task FirstAsync(Expression> select) => this.ToOneAsync(select); } } \ No newline at end of file