## 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:
28810 2019-03-14 16:17:40 +08:00
parent a2e7f62920
commit 2ab59201b0
23 changed files with 287 additions and 108 deletions

View File

@ -8,6 +8,11 @@ using System.Threading.Tasks;
namespace restful.Controllers { namespace restful.Controllers {
public class SongRepository : GuidRepository<Song> {
public SongRepository(IFreeSql fsql) : base(fsql) {
}
}
[Route("restapi/[controller]")] [Route("restapi/[controller]")]
public class SongsController : Controller { public class SongsController : Controller {
@ -17,6 +22,8 @@ namespace restful.Controllers {
public int Id { get; set; } public int Id { get; set; }
} }
public SongsController(IFreeSql fsql, public SongsController(IFreeSql fsql,
GuidRepository<Song> repos1, GuidRepository<Song> repos1,
GuidRepository<xxxx> repos2, GuidRepository<xxxx> repos2,
@ -26,7 +33,9 @@ namespace restful.Controllers {
BaseRepository<Song> repos3, BaseRepository<Song, int> repos4, BaseRepository<Song> repos3, BaseRepository<Song, int> repos4,
IBasicRepository<Song> repos31, IBasicRepository<Song, int> repos41, 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; _songRepository = repos4;
@ -35,6 +44,16 @@ namespace restful.Controllers {
var curd2 = fsql.GetRepository<Song, string>(); var curd2 = fsql.GetRepository<Song, string>();
var curd3 = fsql.GetRepository<Song, Guid>(); var curd3 = fsql.GetRepository<Song, Guid>();
var curd4 = fsql.GetGuidRepository<Song>(); 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] [HttpGet]

View File

@ -1,5 +1,6 @@
using Autofac; using Autofac;
using Autofac.Extensions.DependencyInjection; using Autofac.Extensions.DependencyInjection;
using FreeSql;
using FreeSql.DataAnnotations; using FreeSql.DataAnnotations;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -67,8 +68,9 @@ namespace repository_01 {
var builder = new ContainerBuilder(); var builder = new ContainerBuilder();
builder.RegisterFreeRepository(filter => builder.RegisterFreeRepository(
filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId) filter => filter.Apply<Song>("test", a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId),
this.GetType().Assembly
); );
builder.Populate(services); builder.Populate(services);

View File

@ -1,9 +1,9 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Debug",
"System": "Information", "System": "Warning",
"Microsoft": "Information" "Microsoft": "Warning"
} }
} }
} }

View File

@ -6,7 +6,7 @@ using System.Text;
using System.Linq; using System.Linq;
namespace FreeSql { 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); IDataFilter<TEntity> Apply(string filterName, Expression<Func<TEntity, bool>> filterAndValidateExp);
@ -121,13 +121,20 @@ namespace FreeSql {
if (filterName == null) return false; if (filterName == null) return false;
return _filters.TryGetValue(filterName, out var tryfi) ? tryfi.IsEnabled : 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)>(); 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) if (filterName == null)
throw new ArgumentNullException(nameof(filterName)); throw new ArgumentNullException(nameof(filterName));
if (filterAndValidateExp == null) return this; if (filterAndValidateExp == null) return this;
@ -135,5 +142,12 @@ namespace FreeSql {
_filters.Add((typeof(TEntity), filterName, filterAndValidateExp)); _filters.Add((typeof(TEntity), filterName, filterAndValidateExp));
return this; return this;
} }
~FluentDataFilter() {
this.Dispose();
}
public void Dispose() {
_filters.Clear();
}
} }
} }

View File

@ -9,60 +9,18 @@ using System.Linq;
public static class FreeSqlRepositoryAutofacExtenssions { 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 void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Action<FluentDataFilter> globalDataFilter, params Assembly[] assemblies) {
static ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>> _dicRegisterFreeRepositoryPrivateConvertFilterNotExists = new ConcurrentDictionary<Type, ConcurrentDictionary<string, bool>>();
static void RegisterFreeRepositoryPrivate(ContainerBuilder builder, Action<GlobalDataFilter> globalDataFilter) {
Action<object> funcSetDataFilter = instance => { Utils._globalDataFilter = globalDataFilter;
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);
}
};
builder.RegisterGeneric(typeof(GuidRepository<>)).As( builder.RegisterGeneric(typeof(GuidRepository<>)).As(
typeof(GuidRepository<>), typeof(GuidRepository<>),
@ -70,7 +28,7 @@ public static class FreeSqlRepositoryAutofacExtenssions {
typeof(IBasicRepository<>), typeof(IBasicRepository<>),
typeof(IReadOnlyRepository<>) typeof(IReadOnlyRepository<>)
).OnActivating(a => { ).OnActivating(a => {
funcSetDataFilter(a.Instance); //Utils.SetRepositoryDataFilter(a.Instance);
}).InstancePerDependency(); }).InstancePerDependency();
builder.RegisterGeneric(typeof(DefaultRepository<,>)).As( builder.RegisterGeneric(typeof(DefaultRepository<,>)).As(
@ -79,22 +37,12 @@ public static class FreeSqlRepositoryAutofacExtenssions {
typeof(IBasicRepository<,>), typeof(IBasicRepository<,>),
typeof(IReadOnlyRepository<,>) typeof(IReadOnlyRepository<,>)
).OnActivating(a => { ).OnActivating(a => {
funcSetDataFilter(a.Instance); //Utils.SetRepositoryDataFilter(a.Instance);
}).InstancePerDependency(); }).InstancePerDependency();
}
class ReplaceVisitor : ExpressionVisitor { builder.RegisterAssemblyTypes(assemblies).Where(a => {
private ParameterExpression parameter; 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);
}
} }
} }

View File

@ -18,16 +18,8 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
/// <param name="filter">数据过滤 + 验证</param> /// <param name="filter">数据过滤 + 验证</param>
/// <returns></returns> /// <returns></returns>
public static DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(this IFreeSql that, Expression<Func<TEntity, bool>> filter = null) where TEntity : class { public static DefaultRepository<TEntity, TKey> GetRepository<TEntity, TKey>(this IFreeSql that, Expression<Func<TEntity, bool>> filter = null) where TEntity : class {
return new DefaultRepository<TEntity, TKey>(that, filter);
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>;
} }
static ConcurrentDictionary<Type,
ConcurrentDictionary<Type,
IRepository>
> dicGetRepository = new ConcurrentDictionary<Type, ConcurrentDictionary<Type, IRepository>>();
/// <summary> /// <summary>
/// 返回仓库类,适用 Insert 方法无须返回插入的数据 /// 返回仓库类,适用 Insert 方法无须返回插入的数据
@ -38,12 +30,8 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
/// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param> /// <param name="asTable">分表规则,参数:旧表名;返回:新表名 https://github.com/2881099/FreeSql/wiki/Repository</param>
/// <returns></returns> /// <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 { public static GuidRepository<TEntity> GetGuidRepository<TEntity>(this IFreeSql that, Expression<Func<TEntity, bool>> filter = null, Func<string, string> asTable = null) where TEntity : class {
return new GuidRepository<TEntity>(that, filter, asTable);
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>;
} }
static ConcurrentDictionary<Type, IRepository> dicGetGuidRepository = new ConcurrentDictionary<Type, IRepository>();
/// <summary> /// <summary>
/// 合并两个仓储的设置(过滤+分表),以便查询 /// 合并两个仓储的设置(过滤+分表),以便查询
@ -58,4 +46,13 @@ public static class FreeSqlRepositoryIFreeSqlExtenssions {
foreach (var filter in filters) that.Where<T2>(filter.Value.Expression); foreach (var filter in filters) that.Where<T2>(filter.Value.Expression);
return that.AsTable(repos.AsTableSelectInternal); 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);
}
} }

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Version>0.3.15</Version> <Version>0.3.16</Version>
<Authors>YeXiangQin</Authors> <Authors>YeXiangQin</Authors>
<Description>FreeSql Implementation of General Repository, Support MySql/SqlServer/PostgreSQL/Oracle/Sqlite, and read/write separation、and split table.</Description> <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> <PackageProjectUrl>https://github.com/2881099/FreeSql/wiki/Repository</PackageProjectUrl>

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data.Common;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,6 +10,7 @@ namespace FreeSql {
where TEntity : class { where TEntity : class {
protected IFreeSql _fsql; protected IFreeSql _fsql;
internal DbTransaction _tran;
public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>(); public IDataFilter<TEntity> DataFilter { get; } = new DataFilter<TEntity>();
Func<string, string> _asTableVal; Func<string, string> _asTableVal;
@ -22,10 +24,11 @@ namespace FreeSql {
protected Func<Type, string, string> AsTableSelect { get; private set; } protected Func<Type, string, string> AsTableSelect { get; private set; }
internal Func<Type, string, string> AsTableSelectInternal => AsTableSelect; 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() { protected BaseRepository(IFreeSql fsql, Expression<Func<TEntity, bool>> filter, Func<string, string> asTable = null) : base() {
_fsql = fsql ?? throw new NullReferenceException(nameof(fsql)); _fsql = fsql ?? throw new NullReferenceException(nameof(fsql));
Utils.SetRepositoryDataFilter(this, null);
DataFilter.Apply("", filter); DataFilter.Apply("", filter);
AsTable = asTable; AsTable = asTable;
} }
@ -91,14 +94,14 @@ namespace FreeSql {
public Task<int> UpdateAsync(TEntity entity) => OrmUpdate(entity).ExecuteAffrowsAsync(); public Task<int> UpdateAsync(TEntity entity) => OrmUpdate(entity).ExecuteAffrowsAsync();
protected ISelect<TEntity> OrmSelect(object dywhere) { 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); var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
foreach (var filter in filters) select.Where(filter.Value.Expression); foreach (var filter in filters) select.Where(filter.Value.Expression);
return select.AsTable(AsTableSelect); return select.AsTable(AsTableSelect);
} }
protected IUpdate<TEntity> OrmUpdate(object dywhere) { protected IUpdate<TEntity> OrmUpdate(object dywhere) {
var entityObj = dywhere as TEntity; 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); var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
foreach (var filter in filters) { foreach (var filter in filters) {
if (entityObj != null && filter.Value.ExpressionDelegate?.Invoke(entityObj) == false) if (entityObj != null && filter.Value.ExpressionDelegate?.Invoke(entityObj) == false)
@ -108,14 +111,14 @@ namespace FreeSql {
return update.AsTable(AsTable); return update.AsTable(AsTable);
} }
protected IDelete<TEntity> OrmDelete(object dywhere) { 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); var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
foreach (var filter in filters) delete.Where(filter.Value.Expression); foreach (var filter in filters) delete.Where(filter.Value.Expression);
return delete.AsTable(AsTable); return delete.AsTable(AsTable);
} }
protected IInsert<TEntity> OrmInsert(TEntity entity) => OrmInsert(new[] { entity }); protected IInsert<TEntity> OrmInsert(TEntity entity) => OrmInsert(new[] { entity });
protected IInsert<TEntity> OrmInsert(IEnumerable<TEntity> entitys) { 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); var filters = (DataFilter as DataFilter<TEntity>)._filters.Where(a => a.Value.IsEnabled == true);
foreach (var filter in filters) { foreach (var filter in filters) {
foreach (var entity in entitys) foreach (var entity in entitys)

View File

@ -5,7 +5,7 @@ using System.Threading.Tasks;
namespace FreeSql { namespace FreeSql {
public interface IRepository { public interface IRepository {
Type EntityType { get; }
} }
public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity> public interface IRepository<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>

View 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();
}
}

View 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;
}
}
}

View 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);
}
}
}

View File

@ -41,7 +41,8 @@ namespace FreeSql.Tests.SqlServer {
Assert.Equal(10, g.sqlserver.Insert<Topic>().AppendData(items).ExecuteInserted().Count); 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(); //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 dt1 = select.Limit(10).ToDataTable();
var dt2 = select.Limit(10).ToDataTable("id, getdate()"); var dt2 = select.Limit(10).ToDataTable("id, getdate()");

View File

@ -94,6 +94,10 @@ namespace FreeSql.Tests.SqlServer {
testFieldUShortNullable = ushort.MinValue, testFieldUShortNullable = ushort.MinValue,
testFielLongNullable = long.MinValue testFielLongNullable = long.MinValue
}; };
var sqlPar = insert.AppendData(item2).ToSql();
var sqlText = insert.AppendData(item2).NoneParameter().ToSql();
var item3 = insert.AppendData(item2).ExecuteInserted(); var item3 = insert.AppendData(item2).ExecuteInserted();
var newitem2 = select.Where(a => a.Id == item2.Id).ToOne(); var newitem2 = select.Where(a => a.Id == item2.Id).ToOne();

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Version>0.3.15</Version> <Version>0.3.16</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Authors>YeXiangQin</Authors> <Authors>YeXiangQin</Authors>
<Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description> <Description>FreeSql is the most convenient ORM in dotnet. It supports Mysql, Postgresql, SqlServer, Oracle and Sqlite.</Description>

View File

@ -37,7 +37,7 @@ namespace FreeSql.Internal.CommonProvider {
return this; return this;
} }
public IInsert<T1> NoneParameter() { public IInsert<T1> NoneParameter() {
_noneParameter = false; _noneParameter = true;
return this; return this;
} }

View File

@ -40,7 +40,7 @@ namespace FreeSql.Internal.CommonProvider {
return this; return this;
} }
public IUpdate<T1> NoneParameter() { public IUpdate<T1> NoneParameter() {
_noneParameter = false; _noneParameter = true;
return this; return this;
} }

View File

@ -208,7 +208,7 @@ namespace FreeSql.PostgreSQL {
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) { using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
olddatabase = conn.Value.Database; 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>(); var tables = new List<DbTableInfo>();
foreach (var db in dbs) { 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 max_length = int.Parse(string.Concat(row[3]));
var sqlType = string.Concat(row[4]); var sqlType = string.Concat(row[4]);
var is_nullable = string.Concat(row[5]) == "1"; 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]); var comment = string.Concat(row[7]);
int attndims = int.Parse(string.Concat(row[8])); int attndims = int.Parse(string.Concat(row[8]));
string typtype = string.Concat(row[9]); string typtype = string.Concat(row[9]);

View File

@ -107,7 +107,7 @@ namespace FreeSql.SqlServer {
using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) { using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) {
olddatabase = conn.Value.Database; 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>(); var tables = new List<DbTableInfo>();
foreach (var db in dbs) { foreach (var db in dbs) {