繁体   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