-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
ValueGeneratorCache.cs
84 lines (72 loc) · 3.33 KB
/
ValueGeneratorCache.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Concurrent;
namespace Microsoft.EntityFrameworkCore.ValueGeneration;
/// <summary>
/// <para>
/// Keeps a cache of value generators for properties.
/// </para>
/// <para>
/// This type is typically used by database providers (and other extensions). It is generally
/// not used in application code.
/// </para>
/// </summary>
/// <remarks>
/// <para>
/// The service lifetime is <see cref="ServiceLifetime.Singleton" />. This means a single instance
/// is used by many <see cref="DbContext" /> instances. The implementation must be thread-safe.
/// This service cannot depend on services registered as <see cref="ServiceLifetime.Scoped" />.
/// </para>
/// <para>
/// See <see href="https://aka.ms/efcore-docs-providers">Implementation of database providers and extensions</see>
/// for more information and examples.
/// </para>
/// </remarks>
public class ValueGeneratorCache : IValueGeneratorCache
{
/// <summary>
/// Initializes a new instance of the <see cref="ValueGeneratorCache" /> class.
/// </summary>
/// <param name="dependencies">Parameter object containing dependencies for this service.</param>
public ValueGeneratorCache(ValueGeneratorCacheDependencies dependencies)
{
Dependencies = dependencies;
}
/// <summary>
/// Dependencies for this service.
/// </summary>
protected virtual ValueGeneratorCacheDependencies Dependencies { get; }
private readonly ConcurrentDictionary<CacheKey, ValueGenerator> _cache = new();
private readonly struct CacheKey : IEquatable<CacheKey>
{
public CacheKey(IProperty property, ITypeBase typeBase)
{
Property = property;
TypeBase = typeBase;
}
public IProperty Property { get; }
public ITypeBase TypeBase { get; }
public bool Equals(CacheKey other)
=> Property.Equals(other.Property) && TypeBase.Equals(other.TypeBase);
public override bool Equals(object? obj)
=> obj is CacheKey cacheKey && Equals(cacheKey);
public override int GetHashCode()
=> HashCode.Combine(Property, TypeBase);
}
/// <summary>
/// Gets the existing value generator from the cache, or creates a new one if one is not present in
/// the cache.
/// </summary>
/// <param name="property">The property to get the value generator for.</param>
/// <param name="typeBase">
/// The entity type that the value generator will be used for. When called on inherited properties on derived entity types,
/// this entity type may be different from the declared entity type on <paramref name="property" />
/// </param>
/// <param name="factory">Factory to create a new value generator if one is not present in the cache.</param>
/// <returns>The existing or newly created value generator.</returns>
public virtual ValueGenerator GetOrAdd(
IProperty property,
ITypeBase typeBase,
Func<IProperty, ITypeBase, ValueGenerator> factory)
=> _cache.GetOrAdd(new CacheKey(property, typeBase), static (ck, f) => f(ck.Property, ck.TypeBase), factory);
}