修复queryable内嵌method call expression的时候dbcontext没有被替换,发布x.6.0.32

This commit is contained in:
xuejiaming 2022-09-14 11:32:40 +08:00
parent 265bfd535e
commit 38b53e883a
7 changed files with 186 additions and 37 deletions

View File

@ -1,9 +1,9 @@
:start
::定义版本
set EFCORE2=2.6.0.31
set EFCORE3=3.6.0.31
set EFCORE5=5.6.0.31
set EFCORE6=6.6.0.31
set EFCORE2=2.6.0.32
set EFCORE3=3.6.0.32
set EFCORE5=5.6.0.32
set EFCORE6=6.6.0.32
::删除所有bin与obj下的文件
@echo off

View File

@ -0,0 +1,79 @@
using System.Data;
using Microsoft.EntityFrameworkCore;
using ShardingCore.Core.EntityMetadatas;
using ShardingCore.Core.VirtualRoutes;
using ShardingCore.Core.VirtualRoutes.DataSourceRoutes.RouteRuleEngine;
using ShardingCore.VirtualRoutes.Days;
namespace Sample.AutoCreateIfPresent;
public class Save7DayRoute:AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute<OrderByHour>
{
public override void Configure(EntityMetadataTableBuilder<OrderByHour> builder)
{
builder.ShardingProperty(o => o.CreateTime);
}
/// <summary>
/// 自动定时任务
/// </summary>
/// <returns></returns>
public override bool AutoCreateTableByTime()
{
return true;
}
/// <summary>
/// 下次启动的时候只保留7天的
/// </summary>
/// <returns></returns>
public override DateTime GetBeginTime()
{
return DateTime.Now.AddDays(-7);
}
/// <summary>
/// 路由查询后置处理器
/// must手动指定的情况下无效不会经过这个方法
/// </summary>
/// <param name="dataSourceRouteResult"></param>
/// <param name="shardingRouteUnits"></param>
/// <returns></returns>
protected override List<TableRouteUnit> AfterShardingRouteUnitFilter(DataSourceRouteResult dataSourceRouteResult, List<TableRouteUnit> shardingRouteUnits)
{
var minTail = ShardingKeyToTail(DateTime.Now.AddDays(-7));
return shardingRouteUnits.Where(o => String.Compare(o.Tail, minTail, StringComparison.Ordinal)>=0).ToList();
// if (shardingRouteUnits.Count > 7)
// {
// return shardingRouteUnits.OrderByDescending(o => o.Tail).Take(7).ToList();
// }
//
// return shardingRouteUnits;
}
public override async Task ExecuteAsync()
{
await base.ExecuteAsync();
using (var scope = RouteShardingProvider.ApplicationServiceProvider.CreateScope())
{
using (var defaultDbContext = scope.ServiceProvider.GetService<DefaultDbContext>())
{
var dbConnection = defaultDbContext.Database.GetDbConnection();
if (dbConnection.State != ConnectionState.Open)
{
await dbConnection.OpenAsync();
}
var entityMetadataManager = RouteShardingProvider.GetRequiredService<IEntityMetadataManager>();
var entityMetadata = entityMetadataManager.TryGet(typeof(OrderByHour));
var deleteTail = ShardingKeyToTail(DateTime.Now.AddHours(1).AddDays(-7));
using (var dbCommand = dbConnection.CreateCommand())
{
dbCommand.CommandText =
$"delete from {entityMetadata.LogicTableName}{entityMetadata.TableSeparator}{deleteTail};";
await dbCommand.ExecuteNonQueryAsync();
}
}
}
}
}

View File

@ -16,6 +16,11 @@ using ShardingCore.TableCreator;
namespace Sample.MySql.Controllers
{
public class ssss
{
public string Id { get; set; }
public int C { get; set; }
}
[ApiController]
[Route("[controller]/[action]")]
public class WeatherForecastController : ControllerBase
@ -30,6 +35,11 @@ namespace Sample.MySql.Controllers
_otherDbContext = otherDbContext;
}
public IQueryable<SysUserMod> GetAll()
{
return _defaultTableDbContext.Set<SysUserMod>();
}
[HttpGet]
public async Task<IActionResult> Get()
{
@ -48,6 +58,9 @@ namespace Sample.MySql.Controllers
// using (var tran = _defaultTableDbContext.Database.BeginTransaction())
// {
var sysUserMods = _defaultTableDbContext.Set<SysUserMod>().OrderBy(o=>o.Id).ThenBy(o=>o.Name);
var sysUserMods1 = _defaultTableDbContext.Set<SysUserMod>()
.Select(o => new ssss(){ Id = o.Id, C = GetAll().Count(x => x.Id == o.Id) }).ToList();
var resultX = await _defaultTableDbContext.Set<SysUserMod>()
.Where(o => o.Id == "2" || o.Id == "3").FirstOrDefaultAsync();
var resultY = await _defaultTableDbContext.Set<SysUserMod>().FirstOrDefaultAsync(o => o.Id == "2" || o.Id == "3");

View File

@ -71,6 +71,12 @@ namespace Sample.SqlServer
new ReadNode("X","Data Source=localhost;Initial Catalog=ShardingCoreDBXA123;Integrated Security=True;"),
}}
},ReadStrategyEnum.Loop);
}).AddServiceConfigure(s =>
{
s.AddSingleton<ILoggerFactory>(sp => LoggerFactory.Create(builder =>
{
builder.AddConsole();
}));
}).AddShardingCore();
//services.AddShardingDbContext<DefaultShardingDbContext1>(
// (conn, o) =>

View File

@ -255,5 +255,12 @@ namespace ShardingCore.Extensions
type = type.BaseType;
}
}
public static bool IsMethodReturnTypeQueryableType(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
return typeof(IQueryable).IsAssignableFrom(type);
}
}
}

View File

@ -125,6 +125,12 @@ namespace ShardingCore.Extensions
var newExpression = replaceQueryableVisitor.Visit(source.Expression);
return replaceQueryableVisitor.Source.Provider.CreateQuery(newExpression);
}
internal static IQueryable<TSource> ReplaceDbContextQueryableWithType<TSource>(this IQueryable<TSource> source, DbContext dbContext)
{
DbContextReplaceQueryableVisitor replaceQueryableVisitor = new DbContextReplaceQueryableVisitor(dbContext);
var newExpression = replaceQueryableVisitor.Visit(source.Expression);
return (IQueryable<TSource>)replaceQueryableVisitor.Source.Provider.CreateQuery(newExpression);
}
internal static Expression ReplaceDbContextExpression(this Expression queryExpression, DbContext dbContext)
{
DbContextReplaceQueryableVisitor replaceQueryableVisitor = new DbContextReplaceQueryableVisitor(dbContext);

View File

@ -33,42 +33,43 @@ namespace ShardingCore.Core.Internal.Visitors
// Recurse down to see if we can simplify...
//if (memberExpression.IsMemberQueryable()) //2x,3x 路由 单元测试 分表和不分表
//{
var expression = Visit(memberExpression.Expression);
var expression = Visit(memberExpression.Expression);
// If we've ended up with a constant, and it's a property or a field,
// we can simplify ourselves to a constant
if (expression is ConstantExpression constantExpression)
// If we've ended up with a constant, and it's a property or a field,
// we can simplify ourselves to a constant
if (expression is ConstantExpression constantExpression)
{
object container = constantExpression.Value;
var member = memberExpression.Member;
if (member is FieldInfo fieldInfo)
{
object container = constantExpression.Value;
var member = memberExpression.Member;
if (member is FieldInfo fieldInfo)
object value = fieldInfo.GetValue(container);
if (value is IQueryable queryable)
{
object value = fieldInfo.GetValue(container);
if (value is IQueryable queryable)
{
return ReplaceMemberExpression(queryable);
}
if (value is DbContext dbContext)
{
return ReplaceMemberExpression(dbContext);
}
//return Expression.Constant(value);
return ReplaceMemberExpression(queryable);
}
if (member is PropertyInfo propertyInfo)
if (value is DbContext dbContext)
{
object value = propertyInfo.GetValue(container, null);
if (value is IQueryable queryable)
{
return ReplaceMemberExpression(queryable);
}
if (value is DbContext dbContext)
{
return ReplaceMemberExpression(dbContext);
}
return ReplaceMemberExpression(dbContext);
}
//return Expression.Constant(value);
}
if (member is PropertyInfo propertyInfo)
{
object value = propertyInfo.GetValue(container, null);
if (value is IQueryable queryable)
{
return ReplaceMemberExpression(queryable);
}
if (value is DbContext dbContext)
{
return ReplaceMemberExpression(dbContext);
}
}
}
//}
return base.VisitMember(memberExpression);
@ -85,14 +86,50 @@ namespace ShardingCore.Core.Internal.Visitors
Expression.Property(ConstantExpression.Constant(tempVariable), nameof(TempVariable<object>.Queryable));
return queryableMemberReplaceExpression;
}
private MemberExpression ReplaceMemberExpression(DbContext dbContext)
{
var tempVariableGenericType = typeof(TempDbVariable<>).GetGenericType0(dbContext.GetType());
var tempVariable = Activator.CreateInstance(tempVariableGenericType, _dbContext);
MemberExpression dbContextMemberReplaceExpression =
Expression.Property(ConstantExpression.Constant(tempVariable), nameof(TempDbVariable<object>.DbContext));
Expression.Property(ConstantExpression.Constant(tempVariable),
nameof(TempDbVariable<object>.DbContext));
return dbContextMemberReplaceExpression;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.ReturnType.IsMethodReturnTypeQueryableType()&&node.Method.ReturnType.IsGenericType)
{
#if EFCORE2 || EFCORE3
var notRoot = node.Arguments.All(o => !(o is ConstantExpression constantExpression&&constantExpression.Value is IQueryable));
#endif
#if !EFCORE2 && !EFCORE3
var notRoot = node.Arguments.All(o => !(o is QueryRootExpression));
#endif
if (notRoot)
{
var entityType = node.Method.ReturnType.GenericTypeArguments[0];
var whereCallExpression = ReplaceMethodCallExpression(node, entityType);
return whereCallExpression;
}
}
return base.VisitMethodCall(node);
}
private MethodCallExpression ReplaceMethodCallExpression(MethodCallExpression methodCallExpression,
Type entityType)
{
MethodCallExpression whereCallExpression = Expression.Call(
typeof(IShardingQueryableExtension),
nameof(IShardingQueryableExtension.ReplaceDbContextQueryableWithType),
new Type[] { entityType },
methodCallExpression, Expression.Constant(_dbContext)
);
return whereCallExpression;
}
internal sealed class TempVariable<T1>
{
@ -103,6 +140,7 @@ namespace ShardingCore.Core.Internal.Visitors
Queryable = queryable;
}
}
internal sealed class TempDbVariable<T1>
{
public T1 DbContext { get; }
@ -112,7 +150,6 @@ namespace ShardingCore.Core.Internal.Visitors
DbContext = dbContext;
}
}
}
#if EFCORE2 || EFCORE3
@ -170,9 +207,11 @@ namespace ShardingCore.Core.Internal.Visitors
if (node is QueryRootExpression queryRootExpression)
{
var dbContextDependencies =
typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as
IDbContextDependencies;
var targetIQ =
(IQueryable)((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
(IQueryable)((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource,
queryRootExpression.EntityType.ClrType);
var newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
if (Source == null)
@ -204,5 +243,4 @@ namespace ShardingCore.Core.Internal.Visitors
}
}
#endif
}