簡體   English   中英

EF FromSql()及其相關實體

[英]EF FromSql() with related entities

免責聲明:這些要求不是我設定的,除非這是一項不可能完成的任務,否則我無法說服老板。

假設我們有兩個實體: ItemItemTranslation

public class Item
{
    public int Id { get; set; }

    public string Description { get; set; }

    public virtual ICollection<Item> Children { get; set; }
    public virtual Item Parent { get; set; }
    public virtual ICollection<ItemTranslation> Translations { get; set; }
}

public class ItemTranslation
{
    public int Id { get; set; }

    public string CultureId { get; set; }
    public string Description { get; set; }

    public virtual Item Item { get; set; }
}

要求是Item Description應根據默認選擇的語言進行填寫,但也可以根據用戶的需要指定。 Item Description列實際上在數據庫中不存在。

在SQL中,這很容易:您要做的就是像這樣查詢兩個表

SELECT [Item].[Id], [ItemTranslation].[Description], [Item].[ParentId] 
FROM [Item] 
LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId]  
WHERE [CultureId] = {cultureId}

或根據您的實現使用外部應用。 我已將此查詢添加到實體框架中內置的.FromSql()函數中。

將所有這些放到OData API中,對於一個Item一切正常。 但是,一旦您開始使用$ expand(在幕后是一種.include()),它就不再起作用。 發送到數據庫的相關實體的查詢不再包含我在.FromSql()指定的SQL。 只有第一個查詢。 最重要的是,當您從其他控制器(例如ItemTranslation查詢Item ,這也將不再起作用,因為.FromSql()僅應用於其他控制器。

我可以編寫一個查詢攔截器,該查詢攔截器FROM [Item] LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId] WHERE [CultureId] = {cultureId} Entity Framework替換生成的SQL,然后將FROM [Item]替換為FROM [Item] LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId] WHERE [CultureId] = {cultureId}但我想知道是否有比這更好的實現。 甚至可以重新設計模型。 我願意提出建議。

FromSql有一些局限性 我懷疑這是Include無法起作用的原因。

但是一旦使用EF,為什么要搞亂SQL? 該查詢有哪些困難使您無法在LINQ中進行查詢? 左加入也許?

from item in ctx.Items
from itemTranslation in ctx.ItemTranslations.Where(it => it.Item.Id == item.Id).DefaultIfEmpty()
where itemTranslation.CultureId == cultureId
select new { item.Id, itemTranslation.Description, ParentId = item.Parent.Id };

更新

再次討論這個問題,我看到了另一個問題。 Include僅適用於IQueryable <T> ,其中T是其導航屬性已正確映射的實體。 現在,從這個角度來看,如果使用FromSql或LINQ生成的是某個投影的IQueryable而不是實體,則無所謂, Include顯然不能工作。

為了能夠包含ItemTranslation實體,您的操作方法應如下所示:

[Queryable]
public IQueryable<Item> GetItems()
{
    return db.Items;
}

因此,框架可以對您返回的IQueryable <Item>執行$ expand 但是,這將包括所有項目的翻譯,而不僅僅是具有所需文化的項目。 如果我正確理解,這是您的核心問題。

同樣很明顯,您不能將此區域性過濾器應用於IQueryable <Item> 但是您不應該這樣做,因為這是通過OData中的$ filter實現的:

GET https://.../Items/$expand=Translations&$filter=Translations/CultureId eq culture

暫無
暫無

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

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