EF Core - 动态指定运行时查询哪个表

问题描述 投票:0回答:1

我有很多表可以取。现在,对于每个表,我都有一个控制器类来获取请求,应用查询参数和分页,最后返回结果。它们几乎都是一样的,只是表名不同,这导致了很多文件和很多重复。

因此,我试图创建一个端点并为所有端点提供服务。目标是从路由参数中检测表。

首先我创建了这个属性:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class ResourceAttribute : Attribute
{
    public ResourceAttribute(ResourceType resourceType)
    {
        ResourceType = resourceType;
    }

    public ResourceType ResourceType { get; }
}

public enum ResourceType
{
    Public = 1,
    User,
    Admin
}

Public
表示任何人都可以获取数据,例如:产品。
User
表示该资源可供每个登录用户使用,并且他们不应该看到其他用户的数据,例如:评论、订单。
Admin
表示此资源仅在我们的管理面板中可用,并且不公开,例如:AppSettings。

接下来,我应用属性:

[Resource(ResourceType.Public)]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    // ...
}

然后我创建了一个单例服务来存储所有资源信息:

public class ResourceService
{
    private readonly Dictionary<string, RoutableResource> _resourceMap;

    public ResourceService()
    {
        _resourceMap = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(x => x.GetTypes())
            .Where(x => x.IsDefined(typeof(ResourceAttribute), false))
            .ToDictionary(
                GetResourceRouteName,
                x => new RoutableResource
                {
                    Name = GetResourceRouteName(x),
                    Type = x,
                    ResourceType = GetResourceRouteType(x)
                });

        // ...
    }

    public bool ResourceExists(string resourceName) => _resourceMap.ContainsKey(resourceName);
    public RoutableResource? GetResource(string resourceName) => _resourceMap.GetValueOrDefault(resourceName);
}

public class RoutableResource
{
    public string Name { get; set; }
    public Type Type { get; set; }
    public ResourceType ResourceType { get; set; }
}

这是控制器方法:

[HttpGet("{resourceName}/{id?}")]
public async Task<IActionResult> GetResource(string resourceName, string? id)
{
    if (!_resourceService.ResourceExists(resourceName))
    {
        return NotFound();
    }

    RoutableResource resource = _resourceService.GetResource(resourceName)!;
    
    // Check authorization

    // Get IQueryable of the selected resource 👈 [I'm stuck here]

    // Get all query params and apply them to query with the help of reflection and expressions

    // Get the target ViewModel class from ResourceVM map and apply the projection

    // Finally return the result
}

有一个

DbContext.Set<T>()
但它需要编译时的类型。在这个答案的帮助下,我得到了
IQueryable
,但它没有用。

asp.net-core entity-framework-core npgsql .net-8.0
1个回答
0
投票

如果您确定它们都具有相同的属性,则创建一个接口并在所有 DBO 类型中实现它。然后,使用可以接受所有 DBO 类型的接口类型。

我也不明白为什么你不能这样做?

var tableToQuery;
if(somecondition)
    tableToQuery = dbContext.A;
else
    tableToQuery = dbContext.B;
tableToQuery.query();
© www.soinside.com 2019 - 2024. All rights reserved.