12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- using System;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.EntityFrameworkCore.Metadata.Builders;
- using Microsoft.EntityFrameworkCore.Metadata.Internal;
- using Microsoft.EntityFrameworkCore.Query;
- using System.Collections.ObjectModel;
- namespace MTWorkHR.Infrastructure.Data
- {
- public static class BuilderHasIndexExtensions
- {
- static readonly MethodInfo HasIndexMethod = typeof(BuilderHasIndexExtensions)
- .GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
- .Single(t => t.IsGenericMethod && t.Name == nameof(SetIndex));
- public static void HasIndexOnAllEntities<TEntityInterface>(
- this ModelBuilder builder,
- Expression<Func<TEntityInterface, object>> filterExpression)
- {
- foreach (var type in builder.Model.GetEntityTypes()
- .Where(t => t.BaseType == null)
- .Select(t => t.ClrType)
- .Where(t => typeof(TEntityInterface).IsAssignableFrom(t)))
- {
- builder.SetEntityIndex(
- type,
- filterExpression);
- }
- }
- static void SetEntityIndex<TEntityInterface>(
- this ModelBuilder builder,
- Type entityType,
- Expression<Func<TEntityInterface, object>> filterExpression)
- {
- HasIndexMethod
- .MakeGenericMethod(entityType, typeof(TEntityInterface))
- .Invoke(null, new object[] { builder, filterExpression });
- }
- static void SetIndex<TEntity, TEntityInterface>(
- this ModelBuilder builder,
- Expression<Func<TEntityInterface, object>> filterExpression)
- where TEntityInterface : class
- where TEntity : class, TEntityInterface
- {
- var concreteExpression = filterExpression
- .Convert<TEntityInterface, TEntity>();
- builder.Entity<TEntity>()
- .HasIndex(concreteExpression);
- }
- }
- public static class HasIndexExpressionExtensions
- {
- // This magic is courtesy of this StackOverflow post.
- // https://stackoverflow.com/questions/38316519/replace-parameter-type-in-lambda-expression
- // I made some tweaks to adapt it to our needs - @haacked
- public static Expression<Func<TTarget, object>> Convert<TSource, TTarget>(
- this Expression<Func<TSource, object>> root)
- {
- var visitor = new ParameterTypeVisitor<TSource, TTarget>();
- return (Expression<Func<TTarget, object>>)visitor.Visit(root);
- }
- class ParameterTypeVisitor<TSource, TTarget> : ExpressionVisitor
- {
- private ReadOnlyCollection<ParameterExpression> _parameters;
- protected override Expression VisitParameter(ParameterExpression node)
- {
- return _parameters?.FirstOrDefault(p => p.Name == node.Name)
- ?? (node.Type == typeof(TSource) ? Expression.Parameter(typeof(TTarget), node.Name) : node);
- }
- protected override Expression VisitLambda<T>(Expression<T> node)
- {
- _parameters = VisitAndConvert(node.Parameters, "VisitLambda");
- return Expression.Lambda(Visit(node.Body), _parameters);
- }
- }
- }
- }
|