Get Object with deep level of related entity

▼魔方 西西 提交于 2019-12-02 03:14:17

问题


Suppose I have a entity class with one to one relationship as below:

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; }
}

Now I would like to get a Transaction Object based on TransactionID, in addition I would like to get all my related object from Transaction to TransactionDetail to (TransactionType/TransactionCategory/PaymentMethod/PaymentPayor), which is a two-level data mapping and my function would be like:

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)
                    ))
        );

I feel my code is not that clean and tidy, since for each related entity of Transaction Detail, I am actually including multiple instance of transaction detail...I would like to do something like below which only include one instance of Transaction Detail but entity framework does not allow me to do that:

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)
                    ))
        );

So what would be the efficient way for doing that using EF core? Note here I am using repository pattern so I can't use sql-to-linq expression, but only have to use "Include"/"ThenInclude" operation...


回答1:


I feel my code is not that clean and tidy, since for each related entity of Transaction Detail, I am actually including multiple instance of transaction detail...

This is exactly the intended ("by design")way of including multiple related entities in EF Core. It is explained (with example) in the Loading Related Data - Including multiple levels section of the EF Core documentation:

You may want to include multiple related entities for one of the entities that is being included. For example, when querying Blogs, you include Posts and then want to include both the Author and Tags of the Posts. To do this, you need to specify each include path starting at the root. For example, Blog -> Posts -> Author and Blog -> Posts -> Tags. This does not mean you will get redundant joins, in most cases EF will consolidate the joins when generating SQL.

Note the last paragraph. To recap, every Include / ThenInclude chain represents an entity path to be loaded. Each entity contained in the include paths is included just once.



来源:https://stackoverflow.com/questions/51128340/get-object-with-deep-level-of-related-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!