-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
DbContextFactorySource.cs
68 lines (59 loc) · 3.4 KB
/
DbContextFactorySource.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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace Microsoft.EntityFrameworkCore.Internal;
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public class DbContextFactorySource<TContext> : IDbContextFactorySource<TContext>
where TContext : DbContext
{
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public DbContextFactorySource()
=> Factory = CreateActivator();
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual Func<IServiceProvider, DbContextOptions<TContext>, TContext> Factory { get; }
private static Func<IServiceProvider, DbContextOptions<TContext>, TContext> CreateActivator()
{
var constructors
= typeof(TContext).GetTypeInfo().DeclaredConstructors
.Where(c => c is { IsStatic: false, IsPublic: true } && c.GetParameters().Length != 0)
.ToArray();
if (constructors.Length == 1)
{
var parameters = constructors[0].GetParameters();
if (parameters.Length == 1)
{
var isGeneric = parameters[0].ParameterType == typeof(DbContextOptions<TContext>);
if (isGeneric
|| parameters[0].ParameterType == typeof(DbContextOptions))
{
var optionsParam = Expression.Parameter(typeof(DbContextOptions<TContext>), "options");
var providerParam = Expression.Parameter(typeof(IServiceProvider), "provider");
return Expression.Lambda<Func<IServiceProvider, DbContextOptions<TContext>, TContext>>(
Expression.New(
constructors[0],
isGeneric
? optionsParam
: Expression.Convert(optionsParam, typeof(DbContextOptions))),
providerParam, optionsParam)
.Compile();
}
}
}
var factory = ActivatorUtilities.CreateFactory(typeof(TContext), Type.EmptyTypes);
return (p, _) => (TContext)factory(p, null);
}
}