mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 10:42:52 +08:00
## v0.3.16
- 修复 IInsert/IUpdate.NoneParameter() 设成了反作用的 bug; - 修复 IDbFirst.GetTablesByDatabase() 默认数据库 bool 判断 bug; - 增加 FreeSql.Repository 之 IUnitOfWork 实现,[查看参数资料](https://github.com/2881099/FreeSql/wiki/%e5%b7%a5%e4%bd%9c%e5%8d%95%e5%85%83); - 增加 FreeSql.Repository 继承实现的仓储注入; ```csharp builder.RegisterFreeRepository( filter => filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + Thread.CurrentThread.ManagedThreadId), this.GetType().Assembly ); ```
This commit is contained in:
parent
a2e7f62920
commit
2ab59201b0
@ -8,6 +8,11 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace restful.Controllers {
|
||||
|
||||
public class SongRepository : GuidRepository<Song> {
|
||||
public SongRepository(IFreeSql fsql) : base(fsql) {
|
||||
}
|
||||
}
|
||||
|
||||
[Route("restapi/[controller]")]
|
||||
public class SongsController : Controller {
|
||||
|
||||
@ -17,6 +22,8 @@ namespace restful.Controllers {
|
||||
public int Id { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public SongsController(IFreeSql fsql,
|
||||
GuidRepository<Song> repos1,
|
||||
GuidRepository<xxxx> repos2,
|
||||
@ -26,7 +33,9 @@ namespace restful.Controllers {
|
||||
|
||||
BaseRepository<Song> repos3, BaseRepository<Song, int> repos4,
|
||||
IBasicRepository<Song> repos31, IBasicRepository<Song, int> repos41,
|
||||
IReadOnlyRepository<Song> repos311, IReadOnlyRepository<Song, int> repos411
|
||||
IReadOnlyRepository<Song> repos311, IReadOnlyRepository<Song, int> repos411,
|
||||
|
||||
SongRepository reposSong
|
||||
) {
|
||||
_songRepository = repos4;
|
||||
|
||||
@ -35,6 +44,16 @@ namespace restful.Controllers {
|
||||
var curd2 = fsql.GetRepository<Song, string>();
|
||||
var curd3 = fsql.GetRepository<Song, Guid>();
|
||||
var curd4 = fsql.GetGuidRepository<Song>();
|
||||
|
||||
Console.WriteLine(repos1.Select.ToSql());
|
||||
Console.WriteLine(reposSong.Select.ToSql());
|
||||
|
||||
Console.WriteLine(repos2.Select.ToSql());
|
||||
Console.WriteLine(repos21.Select.ToSql());
|
||||
|
||||
using (reposSong.DataFilter.DisableAll()) {
|
||||
Console.WriteLine(reposSong.Select.ToSql());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using FreeSql;
|
||||
using FreeSql.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
@ -67,8 +68,9 @@ namespace repository_01 {
|
||||
|
||||
var builder = new ContainerBuilder();
|
||||
|
||||
builder.RegisterFreeRepository(filter =>
|
||||
filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId)
|
||||
builder.RegisterFreeRepository(
|
||||
filter => filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId),
|
||||
this.GetType().Assembly
|
||||
);
|
||||
|
||||
builder.Populate(services);
|
||||
|
@ -2,8 +2,8 @@
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
"System": "Warning",
|
||||
"Microsoft": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ using System.Text;
|
||||
using System.Linq;
|
||||
|
||||
namespace FreeSql {
|
||||
public interface IDataFilter<TEntity> where TEntity : class {
|
||||
public interface IDataFilter<TEntity> : IDisposable where TEntity : class {
|
||||
|
||||
IDataFilter<TEntity> Apply(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp);
|
||||
|
||||
@ -121,13 +121,20 @@ namespace FreeSql {
|
||||
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 GlobalDataFilter {
|
||||
public class FluentDataFilter : IDisposable {
|
||||
|
||||
internal List<(Type type, string name, LambdaExpression exp)> _filters = new List<(Type type, string name, LambdaExpression exp)>();
|
||||
|
||||
public GlobalDataFilter Apply<TEntity>(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp) where TEntity : class {
|
||||
public FluentDataFilter Apply<TEntity>(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp) where TEntity : class {
|
||||
if (filterName == null)
|
||||
throw new ArgumentNullException(nameof(filterName));
|
||||
if (filterAndValidateExp == null) return this;
|
||||
@ -135,5 +142,12 @@ namespace FreeSql {
|
||||
_filters.Add((typeof(TEntity), filterName, filterAndValidateExp));
|
||||
return this;
|
||||
}
|
||||
|
||||
~FluentDataFilter() {
|
||||
this.Dispose();
|
||||
}
|
||||
public void Dispose() {
|
||||
_filters.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,60 +9,18 @@ using System.Linq;
|
||||
|
||||
public static class FreeSqlRepositoryAutofacExtenssions {
|
||||
|
||||
public static void RegisterFreeRepository(this ContainerBuilder builder, Action<GlobalDataFilter> globalDataFilter) => RegisterFreeRepositoryPrivate(builder, globalDataFilter);
|
||||
/// <summary>
|
||||
/// 注册 FreeSql.Repository 包括 泛型、继承实现的仓储
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
/// <param name="globalDataFilter">全局过滤设置</param>
|
||||
/// <param name="assemblies">继承实现的仓储,所在的程序集</param>
|
||||
public static void RegisterFreeRepository(this ContainerBuilder builder, Action<FluentDataFilter> globalDataFilter = null, params Assembly[] assemblies) =>
|
||||
RegisterFreeRepositoryPrivate(builder, globalDataFilter, assemblies);
|
||||
|
||||
static ConcurrentDictionary<Type, Delegate> _dicRegisterFreeRepositoryPrivateSetFilterFunc = new ConcurrentDictionary<Type, Delegate>();
|
||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicRegisterFreeRepositoryPrivateConvertFilterNotExists = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
|
||||
static void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Action<GlobalDataFilter> globalDataFilter) {
|
||||
static void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Action<FluentDataFilter> globalDataFilter, params Assembly[] assemblies) {
|
||||
|
||||
Action<object> funcSetDataFilter = instance => {
|
||||
if (globalDataFilter == null) return;
|
||||
var globalFilter = new GlobalDataFilter();
|
||||
globalDataFilter(globalFilter);
|
||||
|
||||
var type = instance.GetType();
|
||||
var entityType = type.GenericTypeArguments[0];
|
||||
|
||||
var notExists = _dicRegisterFreeRepositoryPrivateConvertFilterNotExists.GetOrAdd(type, t => new ConcurrentDictionary<string, bool>());
|
||||
var newFilter = new Dictionary<string, LambdaExpression>();
|
||||
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, gf.exp);
|
||||
}
|
||||
if (newFilter.Any() == false) return;
|
||||
|
||||
var del = _dicRegisterFreeRepositoryPrivateSetFilterFunc.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(instance, nf.Key, nf.Value);
|
||||
}
|
||||
};
|
||||
Utils._globalDataFilter = globalDataFilter;
|
||||
|
||||
builder.RegisterGeneric(typeof(GuidRepository<>)).As(
|
||||
typeof(GuidRepository<>),
|
||||
@ -70,7 +28,7 @@ public static class FreeSqlRepositoryAutofacExtenssions {
|
||||
typeof(IBasicRepository<>),
|
||||
typeof(IReadOnlyRepository<>)
|
||||
).OnActivating(a => {
|
||||
funcSetDataFilter(a.Instance);
|
||||
//Utils.SetRepositoryDataFilter(a.Instance);
|
||||
}).InstancePerDependency();
|
||||
|
||||
builder.RegisterGeneric(typeof(DefaultRepository<,>)).As(
|
||||
@ -79,22 +37,12 @@ public static class FreeSqlRepositoryAutofacExtenssions {
|
||||
typeof(IBasicRepository<,>),
|
||||
typeof(IReadOnlyRepository<,>)
|
||||
).OnActivating(a => {
|
||||
funcSetDataFilter(a.Instance);
|
||||
//Utils.SetRepositoryDataFilter(a.Instance);
|
||||
}).InstancePerDependency();
|
||||
}
|
||||
|
||||
class ReplaceVisitor : ExpressionVisitor {
|
||||
private ParameterExpression parameter;
|
||||
builder.RegisterAssemblyTypes(assemblies).Where(a => {
|
||||
return typeof(IRepository).IsAssignableFrom(a);
|
||||
}).InstancePerDependency();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,16 +18,8 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
|
||||
/// <param name="filter">数据过滤 + 验证</param>
|
||||
/// <returns></returns>
|
||||
public static DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(this IFreeSql that, Expression<Func<TEntity, bool>> filter = null) where TEntity : class {
|
||||
|
||||
if (filter != null) return new DefaultRepository<TEntity, TKey>(that, filter);
|
||||
return dicGetRepository
|
||||
.GetOrAdd(typeof(TEntity), key1 => new ConcurrentDictionary<Type, IRepository>())
|
||||
.GetOrAdd(typeof(TKey), key2 => new DefaultRepository<TEntity, TKey>(that, null)) as DefaultRepository<TEntity, TKey>;
|
||||
return new DefaultRepository<TEntity, TKey>(that, filter);
|
||||
}
|
||||
static ConcurrentDictionary<Type,
|
||||
ConcurrentDictionary<Type,
|
||||
IRepository>
|
||||
> dicGetRepository = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, IRepository>>();
|
||||
|
||||
/// <summary>
|
||||
/// 返回仓库类,适用 Insert 方法无须返回插入的数据
|
||||
@ -38,12 +30,8 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
|
||||
/// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
|
||||
/// <returns></returns>
|
||||
public static GuidRepository<TEntity> GetGuidRepository<TEntity>(this IFreeSql that, Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class {
|
||||
|
||||
if (filter != null || asTable != null) return new GuidRepository<TEntity>(that, filter, asTable);
|
||||
return dicGetGuidRepository
|
||||
.GetOrAdd(typeof(TEntity), key1 => new GuidRepository<TEntity>(that, null, null)) as GuidRepository<TEntity>;
|
||||
return new GuidRepository<TEntity>(that, filter, asTable);
|
||||
}
|
||||
static ConcurrentDictionary<Type, IRepository> dicGetGuidRepository = new ConcurrentDictionary<Type, IRepository>();
|
||||
|
||||
/// <summary>
|
||||
/// 合并两个仓储的设置(过滤+分表),以便查询
|
||||
@ -58,4 +46,13 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
|
||||
foreach (var filter in filters) that.Where<T2>(filter.Value.Expression);
|
||||
return that.AsTable(repos.AsTableSelectInternal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个新的工作单元,务必使用 using 包含使用
|
||||
/// </summary>
|
||||
/// <param name="that"></param>
|
||||
/// <returns></returns>
|
||||
public static IUnitOfWork CreateUnitOfWork(this IFreeSql that) {
|
||||
return new UnitOfWork(that);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Version>0.3.15</Version>
|
||||
<Version>0.3.16</Version>
|
||||
<Authors>YeXiangQin</Authors>
|
||||
<Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table.</Description>
|
||||
<PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/Repository</PackageProjectUrl>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
@ -9,6 +10,7 @@ namespace FreeSql {
|
||||
where TEntity : class {
|
||||
|
||||
protected IFreeSql _fsql;
|
||||
internal DbTransaction _tran;
|
||||
public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>();
|
||||
|
||||
Func<string, string> _asTableVal;
|
||||
@ -22,10 +24,11 @@ namespace FreeSql {
|
||||
protected Func<Type, string, string> AsTableSelect { get; private set; }
|
||||
internal Func<Type, string, string> AsTableSelectInternal => AsTableSelect;
|
||||
|
||||
protected Type EntityType { get; } = typeof(TEntity);
|
||||
public Type EntityType { get; } = typeof(TEntity);
|
||||
|
||||
protected BaseRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable = null) : base() {
|
||||
_fsql = fsql ?? throw new NullReferenceException(nameof(fsql));
|
||||
Utils.SetRepositoryDataFilter(this, null);
|
||||
DataFilter.Apply("", filter);
|
||||
AsTable = asTable;
|
||||
}
|
||||
@ -91,14 +94,14 @@ namespace FreeSql {
|
||||
public Task<int> UpdateAsync(TEntity entity) => OrmUpdate(entity).ExecuteAffrowsAsync();
|
||||
|
||||
protected ISelect<TEntity> OrmSelect(object dywhere) {
|
||||
var select = _fsql.Select<TEntity>(dywhere);
|
||||
var select = _fsql.Select<TEntity>(dywhere).WithTransaction(_tran);
|
||||
var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
|
||||
foreach (var filter in filters) select.Where(filter.Value.Expression);
|
||||
return select.AsTable(AsTableSelect);
|
||||
}
|
||||
protected IUpdate<TEntity> OrmUpdate(object dywhere) {
|
||||
var entityObj = dywhere as TEntity;
|
||||
var update = _fsql.Update<TEntity>(dywhere);
|
||||
var update = _fsql.Update<TEntity>(dywhere).WithTransaction(_tran);
|
||||
var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
|
||||
foreach (var filter in filters) {
|
||||
if (entityObj != null && filter.Value.ExpressionDelegate?.Invoke(entityObj) == false)
|
||||
@ -108,14 +111,14 @@ namespace FreeSql {
|
||||
return update.AsTable(AsTable);
|
||||
}
|
||||
protected IDelete<TEntity> OrmDelete(object dywhere) {
|
||||
var delete = _fsql.Delete<TEntity>(dywhere);
|
||||
var delete = _fsql.Delete<TEntity>(dywhere).WithTransaction(_tran);
|
||||
var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
|
||||
foreach (var filter in filters) delete.Where(filter.Value.Expression);
|
||||
return delete.AsTable(AsTable);
|
||||
}
|
||||
protected IInsert<TEntity> OrmInsert(TEntity entity) => OrmInsert(new[] { entity });
|
||||
protected IInsert<TEntity> OrmInsert(IEnumerable<TEntity> entitys) {
|
||||
var insert = _fsql.Insert<TEntity>(entitys);
|
||||
var insert = _fsql.Insert<TEntity>(entitys).WithTransaction(_tran);
|
||||
var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
|
||||
foreach (var filter in filters) {
|
||||
foreach (var entity in entitys)
|
@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
namespace FreeSql {
|
||||
|
||||
public interface IRepository {
|
||||
|
||||
Type EntityType { get; }
|
||||
}
|
||||
|
||||
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>
|
31
FreeSql.Repository/UnitOfWork/IUnitOfWork.cs
Normal file
31
FreeSql.Repository/UnitOfWork/IUnitOfWork.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
namespace FreeSql {
|
||||
public interface IUnitOfWork : IDisposable {
|
||||
|
||||
/// <summary>
|
||||
/// 在工作单元内创建默认仓库类,工作单元下的仓储操作具有事务特点
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <param name="filter">数据过滤 + 验证</param>
|
||||
/// <returns></returns>
|
||||
DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class;
|
||||
|
||||
/// <summary>
|
||||
/// 在工作单元内创建仓库类,适用 Insert 方法无须返回插入的数据,工作单元下的仓储操作具有事务特点
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <param name="filter">数据过滤 + 验证</param>
|
||||
/// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
|
||||
/// <returns></returns>
|
||||
GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class;
|
||||
|
||||
void Commit();
|
||||
|
||||
void Rollback();
|
||||
}
|
||||
}
|
70
FreeSql.Repository/UnitOfWork/UnitOfWork.cs
Normal file
70
FreeSql.Repository/UnitOfWork/UnitOfWork.cs
Normal file
@ -0,0 +1,70 @@
|
||||
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<DbConnection> _conn;
|
||||
DbTransaction _tran;
|
||||
|
||||
bool _isCommitOrRoolback = false;
|
||||
|
||||
public UnitOfWork(IFreeSql fsql) {
|
||||
_fsql = fsql;
|
||||
}
|
||||
|
||||
DbTransaction BeginTransaction() {
|
||||
_conn = _fsql.Ado.MasterPool.Get();
|
||||
try {
|
||||
_tran = _conn.Value.BeginTransaction();
|
||||
} catch {
|
||||
_fsql.Ado.MasterPool.Return(_conn);
|
||||
_conn = null;
|
||||
throw;
|
||||
}
|
||||
return _tran;
|
||||
}
|
||||
|
||||
public void Commit() {
|
||||
_isCommitOrRoolback = true;
|
||||
if (_conn != null) {
|
||||
try {
|
||||
_tran.Commit();
|
||||
} finally {
|
||||
_fsql.Ado.MasterPool.Return(_conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Rollback() {
|
||||
_isCommitOrRoolback = true;
|
||||
if (_conn != null) {
|
||||
try {
|
||||
_tran.Rollback();
|
||||
} finally {
|
||||
_fsql.Ado.MasterPool.Return(_conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Dispose() {
|
||||
if (_isCommitOrRoolback == false) {
|
||||
this.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(Expression<Func<TEntity, bool>> filter = null) where TEntity : class {
|
||||
var repos = new DefaultRepository<TEntity, TKey>(_fsql, filter);
|
||||
repos._tran = BeginTransaction();
|
||||
return repos;
|
||||
}
|
||||
public GuidRepository<TEntity> GetGuidRepository<TEntity>(Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class {
|
||||
var repos = new GuidRepository<TEntity>(_fsql, filter, asTable);
|
||||
repos._tran = BeginTransaction();
|
||||
return repos;
|
||||
}
|
||||
}
|
||||
}
|
90
FreeSql.Repository/Utils.cs
Normal file
90
FreeSql.Repository/Utils.cs
Normal file
@ -0,0 +1,90 @@
|
||||
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 Utils {
|
||||
|
||||
internal static Action<FluentDataFilter> _globalDataFilter;
|
||||
|
||||
static ConcurrentDictionary<Type, Delegate> _dicSetRepositoryDataFilterApplyDataFilterFunc = new ConcurrentDictionary<Type, Delegate>();
|
||||
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicSetRepositoryDataFilterConvertFilterNotExists = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
|
||||
internal static void SetRepositoryDataFilter(object repos, Action<FluentDataFilter> 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<string, bool>());
|
||||
var newFilter = new Dictionary<string, LambdaExpression>();
|
||||
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, gf.exp);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -41,7 +41,8 @@ namespace FreeSql.Tests.SqlServer {
|
||||
Assert.Equal(10, g.sqlserver.Insert<Topic>().AppendData(items).ExecuteInserted().Count);
|
||||
|
||||
//items = Enumerable.Range(0, 9989).Select(a => new Topic { Title = "newtitle" + a, CreateTime = DateTime.Now }).ToList();
|
||||
//Assert.Equal(9989, g.sqlserver.Insert<Topic>(items).ExecuteAffrows());
|
||||
//;
|
||||
//Assert.Equal(9989, g.sqlserver.Insert<Topic>(items).NoneParameter().ExecuteAffrows());
|
||||
|
||||
var dt1 = select.Limit(10).ToDataTable();
|
||||
var dt2 = select.Limit(10).ToDataTable("id, getdate()");
|
||||
|
@ -94,6 +94,10 @@ namespace FreeSql.Tests.SqlServer {
|
||||
testFieldUShortNullable = ushort.MinValue,
|
||||
testFielLongNullable = long.MinValue
|
||||
};
|
||||
|
||||
var sqlPar = insert.AppendData(item2).ToSql();
|
||||
var sqlText = insert.AppendData(item2).NoneParameter().ToSql();
|
||||
|
||||
var item3 = insert.AppendData(item2).ExecuteInserted();
|
||||
var newitem2 = select.Where(a => a.Id == item2.Id).ToOne();
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Version>0.3.15</Version>
|
||||
<Version>0.3.16</Version>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<Authors>YeXiangQin</Authors>
|
||||
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>
|
||||
|
@ -37,7 +37,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
return this;
|
||||
}
|
||||
public IInsert<T1> NoneParameter() {
|
||||
_noneParameter = false;
|
||||
_noneParameter = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace FreeSql.Internal.CommonProvider {
|
||||
return this;
|
||||
}
|
||||
public IUpdate<T1> NoneParameter() {
|
||||
_noneParameter = false;
|
||||
_noneParameter = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ namespace FreeSql.PostgreSQL {
|
||||
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
|
||||
olddatabase = conn.Value.Database;
|
||||
}
|
||||
var dbs = database?.ToArray() ?? new[] { olddatabase };
|
||||
var dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
|
||||
var tables = new List<DbTableInfo>();
|
||||
|
||||
foreach (var db in dbs) {
|
||||
@ -301,7 +301,7 @@ where ns.nspname || '.' || c.relname in ({loc8})";
|
||||
var max_length = int.Parse(string.Concat(row[3]));
|
||||
var sqlType = string.Concat(row[4]);
|
||||
var is_nullable = string.Concat(row[5]) == "1";
|
||||
var is_identity = string.Concat(row[6]).StartsWith(@"nextval('") && string.Concat(row[6]).EndsWith(@"_seq'::regclass)");
|
||||
var is_identity = string.Concat(row[6]).StartsWith(@"nextval('") && string.Concat(row[6]).EndsWith(@"'::regclass)");
|
||||
var comment = string.Concat(row[7]);
|
||||
int attndims = int.Parse(string.Concat(row[8]));
|
||||
string typtype = string.Concat(row[9]);
|
||||
|
@ -107,7 +107,7 @@ namespace FreeSql.SqlServer {
|
||||
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
|
||||
olddatabase = conn.Value.Database;
|
||||
}
|
||||
var dbs = database?.ToArray() ?? new[] { olddatabase };
|
||||
var dbs = database == null || database.Any() == false ? new[] { olddatabase } : database;
|
||||
var tables = new List<DbTableInfo>();
|
||||
|
||||
foreach (var db in dbs) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user