获取具有深层相关实体的对象

时间:2018-07-02 02:04:56

标签: c# entity-framework-core

假设我有一个具有一对一关系的实体类,如下所示:

public class Transaction
{
    public int TransactionID { get; set; }
    public Double Amount { get; set; }
    public int TransactionDetailID { get; set; }

    public virtual TransactionDetail TransactionDetailFk { get; set; }
}
public class TransactionDetail
{
    public int TransactionDetailID { get; set; }
    public DateTime PostedDate { get; set; }
    public int TransactionTypeID { get; set; }
    public int TransactionCategoryID { get; set; }
    public int PaymentMethodID { get; set; }
    public int PaymentPayorID { get; set; }

    public virtual TransactionType TransactionTypeFk { get; set; }
    public virtual TransactionCategory TransactionCategoryFk { get; set; }
    public virtual PaymentMethod PaymentMethodFk { get; set; }
    public virtual PaymentPayor PaymentPayorFk { get; set; }
    public virtual Transaction TransactionFk { get; set; }
}

现在,我想获取基于TransactionID的交易对象,此外,我还希望将所有与交易相关的对象从Transaction转到TransactionDetail  到(TransactionType / TransactionCategory / PaymentMethod / PaymentPayor),这是一个两级数据映射,我的功能将是:

public async Task<Transaction> GetSingleFullTransactionByIDAsync(int transactionID)
    => await GetSingleOrDefaultAsync(
            predicate: tr => (tr.TransactionID == transactionID),
            include: (obj => (
                            obj
                            .Include(entity => entity.TransactionDetailFk)
                                .ThenInclude(td => td.PaymentPayorFk)
                            .Include(entity => entity.TransactionDetailFk)
                                .ThenInclude(td => td.PaymentMethodFk)
                            .Include(entity => entity.TransactionDetailFk)
                                .ThenInclude(td => td.TransactionTypeFk)
                            .Include(entity => entity.TransactionDetailFk)
                                .ThenInclude(td => td.TransactionCategoryFk)
                    ))
        );

我觉得我的代码不是那么干净整洁,因为对于交易明细的每个相关实体,我实际上包括了交易明细的多个实例...我想在下面做类似的事情,其中​​仅包括一个交易明细细节,但实体框架不允许我这样做:

public async Task<Transaction> GetSingleFullTransactionByIDAsync(int transactionID)
    => await GetSingleOrDefaultAsync(
            predicate: tr => (tr.TransactionID == transactionID),
            include: (obj => (
                            obj
                            .Include(entity => entity.TransactionDetailFk)
                                .ThenInclude(td => td.PaymentPayorFk)
                                .ThenInclude(td => td.PaymentMethodFk)
                                .ThenInclude(td => td.TransactionTypeFk)
                                .ThenInclude(td => td.TransactionCategoryFk)
                    ))
        );

那么使用EF内核实现此目的的有效方法是什么?注意这里我使用的是存储库模式,所以我不能使用sql-to-linq表达式,而只需要使用“ Include” /“ ThenInclude”操作...

1 个答案:

答案 0 :(得分:2)

  

我觉得我的代码不是那么整洁,因为对于交易明细的每个相关实体,我实际上包括了交易明细的多个实例...

这正是在EF Core中包括多个相关实体的预期(“设计”)方式。 EF Core文档的Loading Related Data - Including multiple levels部分对此进行了解释(带有示例):

  

您可能要为所包含的实体之一包含多个相关实体。例如,查询博客时,您要包含“帖子”,然后要同时包含帖子的“作者”和“标签”。为此,您需要指定每个从根开始的包含路径。例如,博客->帖子->作者和博客->帖子->标签。这并不意味着您将获得多余的联接,在大多数情况下,EF会在生成SQL时合并联接。

注意最后一段。概括地说,每个Include / ThenInclude链都代表要加载的实体 path 。包含路径中包含的每个实体仅包含一次。