簡體   English   中英

Entity Framework Core 在沒有 T 的情況下使用 Dbset

[英]Entity Framework Core use Dbset without having T

我希望能夠在 Dbset 中使用類型而不是 T

例如 Dbset(myType) 而不是 DbSet

EF 核心 3.1 要求您使用 DbSet,並且所有功能都封裝在擴展方法中。

這是我為 EF 3.1 使用的解決方案

希望既然我已經經歷過痛苦,我可以為下一個必須這樣做的可憐靈魂分享我的解決方案。

用法

var dbSet = new DbSetFacade(myType);
dynamic results = await dbSet.ToListAsync();

我現在只分享 ToList,Count 以保持簡短!

public class DbSetFacade
{
    private static ReadOnlyDictionary<EfQueryExtensionType, MethodInfo> _extensionMethodInfos = GetExtensionMethodInfos();

    private readonly object _dbSet;
    private readonly ReadOnlyDictionary<EfQueryExtensionType, MethodInfo> _genericInstanceMethodInfos;

    public DbSetFacade(DbContext context, Type entityType)
    {
        if (context == null) throw new ArgumentNullException(nameof(context));
        if (entityType == null) throw new ArgumentNullException(nameof(entityType));

        _dbSet = GetDbSetInstance(context, entityType);

        _genericInstanceMethodInfos = new ReadOnlyDictionary<EfQueryExtensionType, MethodInfo>(new Dictionary<EfQueryExtensionType, MethodInfo>
        {
            [EfQueryExtensionType.AsNoTracking] = _extensionMethodInfos[EfQueryExtensionType.AsNoTracking].MakeGenericMethod(entityType),
            [EfQueryExtensionType.ToListAsync] = _extensionMethodInfos[EfQueryExtensionType.ToListAsync].MakeGenericMethod(entityType),
            [EfQueryExtensionType.CountAsyncWithoutPredicate] = _extensionMethodInfos[EfQueryExtensionType.CountAsyncWithoutPredicate].MakeGenericMethod(entityType),
        });
    }

    enum EfQueryExtensionType
    {
        AsNoTracking,
        ToListAsync,
        //FirstOrDefaultAsyncWithPredicate,
        //FirstOrDefaultAsyncWithoutPredicate,
        //ContainsAsync,
        //CountAsyncWithPredicate,
        CountAsyncWithoutPredicate
    }

    public Task<int> CountAsync(CancellationToken token = default) => _genericInstanceMethodInfos[EfQueryExtensionType.CountAsyncWithoutPredicate].Invoke(null, new object[] { _dbSet, token }) as Task<int>;


    public async Task<dynamic> ToListAsync(CancellationToken token = default)
    {
        var noTrackingSet = _genericInstanceMethodInfos[EfQueryExtensionType.AsNoTracking].Invoke(null, new object[] { _dbSet });
        var toList = _genericInstanceMethodInfos[EfQueryExtensionType.ToListAsync].Invoke(null, new object[] { noTrackingSet, token }) as Task;

        await toList.ConfigureAwait(false);

        return (object)((dynamic)toList).Result;
    }

    private static object GetDbSetInstance(DbContext context, Type type)
    {
        return typeof(DbContext).GetMethods()
            .FirstOrDefault(p => p.Name == "Set" && p.ContainsGenericParameters)
            .MakeGenericMethod(type)
            .Invoke(context, null);
    }

    static ReadOnlyDictionary<EfQueryExtensionType, MethodInfo> GetExtensionMethodInfos()
    {
        var extensionMethods = typeof(EntityFrameworkQueryableExtensions)
            .GetTypeInfo()
            .GetMethods()
            .Where(x => x.ContainsGenericParameters && x.GetParameters()[0].ParameterType.IsGenericType);

        return new ReadOnlyDictionary<EfQueryExtensionType, MethodInfo>(new Dictionary<EfQueryExtensionType, MethodInfo>
        {
            [EfQueryExtensionType.AsNoTracking] = extensionMethods.FirstOrDefault(x => x.Name == "AsNoTracking"),
            [EfQueryExtensionType.ToListAsync] = extensionMethods.FirstOrDefault(x => x.Name == "ToListAsync" && x.GetParameters().Count() == 2),
            [EfQueryExtensionType.CountAsyncWithoutPredicate] = extensionMethods.FirstOrDefault(x => x.Name == "CountAsync" && x.GetParameters().Count() == 2)
        });
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM