将不同的IQueryable提供程序组合为一个是否可行?

时间:2018-10-27 15:03:27

标签: c# architecture iqueryable

困境的介绍

假设我要构建一个OData API来访问EDM,如下所示:

public class ApiUser
{
    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public ICollection<ApiTransaction> Transactions { get; set; }
}

public class ApiTransaction
{
    public Guid Id { get; set; }
    public DateTime TimeStamp { get; set; }
    public decimal Amount { get; set; }

    public ApiUser Account { get; set; }
}

两个实体,具有一对多关系和导航属性。当我经典地为此目的构建API时,考虑到我的商店受它支持(例如SQL Server),我会选择自己喜欢的ORM(例如EntityFramework)并以此构建我的API。

实现OData端点很容易完成,因为有多个软件包可以从我的ORM中获取一个 IQueryable 并将其应用OData查询语言->因此,我基本上已经创建了一个可映射的代理直接连接到SQL Server数据库的OData接口。很整齐。

但是现在微服务风行一时,我们希望将商店分开。由于交易是其自己的业务领域,因此它们处于不同的服务中。也许它们的存储方式也完全不同。一个在SQL DB中,另一个在Cosmos中,其他实体可能在Redis中,等等。 归根结底,这些存储库服务的最大共同点是,它们都提供了将其模型公开为IQueryable <>的客户端,而我们的持久性模型看起来更像这样:

public class DbUser
{
    public Guid Id { get; set; }
    public string UserName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class DbTransaction
{
    public Guid Id { get; set; }
    public DateTime TimeStamp { get; set; }
    public decimal Amount { get; set; }

    public Guid AccountId { get; set; }
}

注意如何没有更多的导航属性。我们的API仍应允许跨实体进行OData查询,但是如果没有导航属性,就无法实现,而无需实现每种情况的导航属性并进行专门处理。

所以我的目标是拥有一个具有导航属性的OData端点,例如第一个代码片段,但让它们持久保存在具有第二个代码片段等模型的潜在供应商中。

我计划好的方法

满足我现在虚构的 CombinedQueryableContextBuilder

var builder = new CombinedQueryableContextBuilder();

builder.RegisterQueryableProvider<UserStoreClient>((entityMap) =>
    entityMap.Add<ApiUser, DbUser>((userStoreClient) => userStoreClient.Users));
builder.RegisterQueryableProvider<TransactionStoreClient>((entityMap) =>
    entityMap.Add<ApiTransaction, DbTransaction>((transactionStoreClient) => transactionStoreClient.Transactions));

var combinedQueryableContext = builder.BuildByConvention(conventionOptions => ...);

var apiUsers = combinedQueryableContext.GetEntitySet<ApiUser>();

var millionaires = apiUsers.Where(user => user.Transaction.Sum(tx => tx.Amount) >= 1_000_000m).ToList();

要给出一些关于它应该做什么的上下文:我有一个Web api,需要公开一个odata上下文终结点,该终结点引用所有Api模型以及它们之间的导航属性。这些模型可能存储在不同的上下文/提供者中,因此现在有了一个组合器,它可以执行魔术操作并查询多个不同的存储库,以满足它们之间导航属性的需求。组合器可以使用约定来确定如何实现表达式。

我对Queryable提供程序知之甚少,而表达式树是我尚未完全了解的东西。 (对我来说,ORM的工作对我来说仍然是一门妖术,但我愿意花时间学习)

问题

那里有一个包装吗,已经这样做了吗?

我上面所描述的甚至可以实现吗?

如果是的话,它是否适合大规模应用? (我对此没有什么特别的考虑,但是也许会有一些陷阱导致数以千计的查询执行,而执行某些执行计划很难避免这些查询执行,而当达到某个阈值/限制时只是中止操作。我不知道我对数据库内部知识也不了解很多,这个合并器基本上就是一个使用多个其他DB作为源的DB)

0 个答案:

没有答案