免责声明:我没有设定这些要求,除非这是一项不可能完成的任务,否则我不能说服老板。
假设我们有两个实体:Item
和ItemTranslation
。
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}
或根据您的实现使用外部应用。我已将此查询添加到Entity Framework中内置的.FromSql()
函数中。
将这些全部放到OData API中,并且对于一个Item
来说一切正常。但是,一旦您开始使用$ expand(在幕后是一种.include()),它就不再起作用。发送到数据库的相关实体的查询不再包含我在.FromSql()
中指定的SQL。只有第一个查询。最重要的是,当您从其他控制器查询Item
时,例如ItemTranslation
也将不再起作用,因为.FromSql()
仅应用于其他控制器。
我可以编写一个查询拦截器,该拦截器仅用Entity Framework替换生成的SQL,并用FROM [Item]
替换FROM [Item] LEFT JOIN [ItemTranslation] ON [Item].[Id] = [ItemTranslation].[ItemId] WHERE [CultureId] = {cultureId}
,但是我想知道是否有比这更好的实现。甚至可以重新设计模型。我愿意接受建议。
答案 0 :(得分:0)
FromSql 有一些limitations。我怀疑这是 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
要能够包含 ItemTranslation 实体,您的操作方法应如下所示:
[Queryable]
public IQueryable<Item> GetItems()
{
return db.Items;
}
因此该框架可以对您返回的 IQueryable
很明显,您不能将此区域性过滤器应用于 IQueryable
GET https://.../Items/$expand=Translations&$filter=Translations/CultureId eq culture