mirror of
https://github.com/nsnail/FreeSql.git
synced 2025-04-22 02:32:50 +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 {
|
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]
|
||||||
|
@ -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);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Debug",
|
"Default": "Debug",
|
||||||
"System": "Information",
|
"System": "Warning",
|
||||||
"Microsoft": "Information"
|
"Microsoft": "Warning"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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>
|
||||||
|
@ -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)
|
@ -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>
|
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);
|
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()");
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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]);
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user