Skip to content

Commit

Permalink
Improve CacheDependencies to works with query hints, Close #225
Browse files Browse the repository at this point in the history
  • Loading branch information
VahidN committed Jan 19, 2024
1 parent a8a8ccd commit 5b708fa
Show file tree
Hide file tree
Showing 3 changed files with 220 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Entity Framework Core Second Level Caching Library.</Description>
<VersionPrefix>4.1.1</VersionPrefix>
<VersionPrefix>4.1.2</VersionPrefix>
<Authors>Vahid Nasiri</Authors>
<TargetFrameworks>net8.0;net7.0;net6.0;net5.0;netstandard2.1;netstandard2.0;net462;netcoreapp3.1;</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
Expand Down
89 changes: 48 additions & 41 deletions src/EFCoreSecondLevelCacheInterceptor/EFSqlCommandsProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,39 @@ namespace EFCoreSecondLevelCacheInterceptor;
/// </summary>
public class EFSqlCommandsProcessor : IEFSqlCommandsProcessor
{
private static readonly string[] CrudMarkers = { "MERGE ", "insert ", "update ", "delete ", "create " };
private static readonly string[] CrudMarkers =
{
"MERGE ", "insert ", "update ", "delete ", "create "
};

private static readonly Type IEntityType =
Type.GetType("Microsoft.EntityFrameworkCore.Metadata.IEntityType, Microsoft.EntityFrameworkCore") ??
throw new TypeLoadException("Couldn't load Microsoft.EntityFrameworkCore.Metadata.IEntityType");

private static readonly PropertyInfo ClrTypePropertyInfo =
IEntityType.GetInterfaces()
.Union(new[] { IEntityType })
.Select(i => i.GetProperty("ClrType", BindingFlags.Public | BindingFlags.Instance))
.Distinct()
.FirstOrDefault(propertyInfo => propertyInfo != null) ??
throw new KeyNotFoundException("Couldn't find `ClrType` on IEntityType.");
private static readonly PropertyInfo ClrTypePropertyInfo = IEntityType.GetInterfaces().Union(new[]
{
IEntityType
}).Select(i => i.GetProperty("ClrType",
BindingFlags.Public | BindingFlags.Instance))
.Distinct()
.FirstOrDefault(propertyInfo
=> propertyInfo != null) ??
throw new KeyNotFoundException(
"Couldn't find `ClrType` on IEntityType.");

private static readonly Type RelationalEntityTypeExtensionsType =
Type.GetType(
"Microsoft.EntityFrameworkCore.RelationalEntityTypeExtensions, Microsoft.EntityFrameworkCore.Relational") ??
"Microsoft.EntityFrameworkCore.RelationalEntityTypeExtensions, Microsoft.EntityFrameworkCore.Relational") ??
throw new TypeLoadException("Couldn't load Microsoft.EntityFrameworkCore.RelationalEntityTypeExtensions");

private static readonly MethodInfo GetTableNameMethodInfo =
RelationalEntityTypeExtensionsType.GetMethod("GetTableName", BindingFlags.Static | BindingFlags.Public)
?? throw new KeyNotFoundException("Couldn't find `GetTableName()` on RelationalEntityTypeExtensions.");
RelationalEntityTypeExtensionsType.GetMethod("GetTableName", BindingFlags.Static | BindingFlags.Public) ??
throw new KeyNotFoundException("Couldn't find `GetTableName()` on RelationalEntityTypeExtensions.");

private static readonly string[] Separator = { "." };
private static readonly string[] Separator =
{
"."
};

private readonly ConcurrentDictionary<string, Lazy<SortedSet<string>>> _commandTableNames =
new(StringComparer.OrdinalIgnoreCase);
Expand All @@ -47,8 +56,8 @@ public class EFSqlCommandsProcessor : IEFSqlCommandsProcessor
/// <summary>
/// SqlCommands Utils
/// </summary>
public EFSqlCommandsProcessor(IEFHashProvider hashProvider) =>
_hashProvider = hashProvider ?? throw new ArgumentNullException(nameof(hashProvider));
public EFSqlCommandsProcessor(IEFHashProvider hashProvider)
=> _hashProvider = hashProvider ?? throw new ArgumentNullException(nameof(hashProvider));

/// <summary>
/// Is `insert`, `update` or `delete`?
Expand Down Expand Up @@ -86,9 +95,8 @@ public IList<TableEntityInfo> GetAllTableNames(DbContext context)
}

return _contextTableNames.GetOrAdd(context.GetType(),
_ => new Lazy<List<TableEntityInfo>>(() => getTableNames(context),
LazyThreadSafetyMode
.ExecutionAndPublication)).Value;
_ => new Lazy<List<TableEntityInfo>>(() => getTableNames(context),
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}

/// <summary>
Expand All @@ -98,11 +106,8 @@ public SortedSet<string> GetSqlCommandTableNames(string commandText)
{
var commandTextKey = $"{_hashProvider.ComputeHash(commandText):X}";
return _commandTableNames.GetOrAdd(commandTextKey,
_ =>
new
Lazy<SortedSet<
string>>(() => getRawSqlCommandTableNames(commandText),
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
_ => new Lazy<SortedSet<string>>(() => getRawSqlCommandTableNames(commandText),
LazyThreadSafetyMode.ExecutionAndPublication)).Value;
}

/// <summary>
Expand All @@ -112,8 +117,7 @@ public IList<Type> GetSqlCommandEntityTypes(string commandText, IList<TableEntit
{
var commandTableNames = GetSqlCommandTableNames(commandText);
return allEntityTypes.Where(entityType => commandTableNames.Contains(entityType.TableName))
.Select(entityType => entityType.ClrType)
.ToList();
.Select(entityType => entityType.ClrType).ToList();
}

private static List<TableEntityInfo> getTableNames(DbContext context)
Expand All @@ -122,21 +126,21 @@ private static List<TableEntityInfo> getTableNames(DbContext context)
foreach (var entityType in context.Model.GetEntityTypes())
{
var clrType = getClrType(entityType);
tableNames.Add(
new TableEntityInfo
{
ClrType = clrType,
TableName = getTableName(entityType) ?? clrType.ToString(),
});
tableNames.Add(new TableEntityInfo
{
ClrType = clrType,
TableName = getTableName(entityType) ?? clrType.ToString()
});
}

return tableNames;
}

private static string? getTableName(object entityType)
{
return GetTableNameMethodInfo.Invoke(null, new[] { entityType }) as string;
}
=> GetTableNameMethodInfo.Invoke(null, new[]
{
entityType
}) as string;

private static Type getClrType(object entityType)
{
Expand All @@ -147,12 +151,17 @@ private static Type getClrType(object entityType)

private static SortedSet<string> getRawSqlCommandTableNames(string commandText)
{
string[] tableMarkers = { "FROM", "JOIN", "INTO", "UPDATE", "MERGE" };
string[] tableMarkers =
{
"FROM", "JOIN", "INTO", "UPDATE", "MERGE"
};

var tables = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);

var sqlItems = commandText.Split(new[] { " ", "\r\n", Environment.NewLine, "\n" },
StringSplitOptions.RemoveEmptyEntries);
var sqlItems = commandText.Split(new[]
{
" ", "\r\n", Environment.NewLine, "\n"
}, StringSplitOptions.RemoveEmptyEntries);
var sqlItemsLength = sqlItems.Length;
for (var i = 0; i < sqlItemsLength; i++)
{
Expand All @@ -166,7 +175,7 @@ private static SortedSet<string> getRawSqlCommandTableNames(string commandText)
++i;
if (i >= sqlItemsLength)
{
continue;
break;
}

var tableName = string.Empty;
Expand All @@ -187,10 +196,8 @@ private static SortedSet<string> getRawSqlCommandTableNames(string commandText)
}

tableName = tableName.Replace("[", "", StringComparison.Ordinal)
.Replace("]", "", StringComparison.Ordinal)
.Replace("'", "", StringComparison.Ordinal)
.Replace("`", "", StringComparison.Ordinal)
.Replace("\"", "", StringComparison.Ordinal);
.Replace("]", "", StringComparison.Ordinal).Replace("'", "", StringComparison.Ordinal)
.Replace("`", "", StringComparison.Ordinal).Replace("\"", "", StringComparison.Ordinal);
tables.Add(tableName);
}
}
Expand Down
Loading

0 comments on commit 5b708fa

Please sign in to comment.