Entity Framework,仓储模式和let语句

3
尝试使用Entity Framework实现正确的存储库模式时,我在使用let语句时遇到了一些问题。我的目标是:
var customer = (from cus in Customers.GetAll()
                let brokerExists = InsuredBrokers.GetAll().Any(ib => ib.INS_Id == cus.INS_Id)
            // ... more stuff

但是这会给我一个错误

System.NotSupportedException:“LINQ to Entities不识别方法'System.Linq.IQueryable`1[SNIP.DataModel.EA_INB_InsuredBrokers_TB] GetAll()'方法,此方法无法转换为存储表达式。”

我可以做的是:

var customer = (from cus in Customers.GetAll()
            let brokerExists = _context.Set<EA_INB_InsuredBrokers_TB>().Any(ib => ib.INS_Id == cus.INS_Id)
            // ... more stuff

然而,这样做破坏了使用存储库模式的任何意义。当我搜索答案时,人们说要将其放在单独的查询中并从内存中引用它,但由于我实际上在let语句中拥有客户端的Id(INS_Id),所以我无法这样做。 GetAll()类似于:
public IQueryable<T> GetAll()
{
    return _context.Set<T>().AsQueryable();
}

有没有什么聪明的方法来规避这个问题?

Customers 是你的仓储实例吗? - Mafii
这个仓储层真的给你带来了好处吗?还是只是限制了你?问问自己,如果可以没有它,那么是否需要。此外,客户到经纪人之间是否有导航属性? - Gert Arnold
1
顺便说一句,我同意Gert的观点——许多在SO上的问题都涉及使用EF仓库,但我仍然不知道为什么需要这样做。EF上下文已经实现了仓库模式——我不明白为什么还需要一个额外的仓库。 - Evk
我询问导航属性的原因是它可以使查询变得更加容易,并且独立于存储库实现。类似于 let brokerExists = cus.Broker != null 或者 let brokerExists = cus.Brokers.Any() 这样的语句。 - Gert Arnold
@GertArnold 你是正确的。但是我们接手了一个起源于90年代的数据库。外键非常少见,我不确定我是否被允许添加任何外键。但也许我可以仅在EF端添加它们... - SamiHuutoniemi
显示剩余3条评论
2个回答

2
你需要将InsuredBrokers.GetAll()移出查询操作:
var allBrokers = InsuredBrokers.GetAll();
var customer = (from cus in Customers.GetAll()
            let brokerExists = allBrokers.Any(ib => ib.INS_Id == cus.INS_Id)
        // ... more stuff

那么它将正常工作。由于 GetAll 返回 IQueryable 并且您没有枚举它-这没有负面影响,并且仍将有一个查询到数据库,就像您在 _context 示例中一样。

原因是 let 语句编译为:

Customers.GetAll().Select(cus => new {cus, brokerExists = InsuredBrokers.GetAll().Any(ib => ib.INS_Id == cus.INS_Id)}

这意味着您对InsuredBrokers.GetAll()的调用是表达式树的一部分(它在

当然,你是正确的。这是一个非常简单的解决方案。需要将它放在外面有点丑陋,但我猜没有更好的方法来做到这一点。 - SamiHuutoniemi
@SamiHuutoniemi,我已经添加了一些关于为什么它像这样工作的解释。 - Evk
但是考虑到我们可以通过在外部创建查询来拆分它,人们可能认为LINQ To Entities足够聪明以处理它。感谢您的帮助! - SamiHuutoniemi
1
如果你想知道为什么你可以在表达式树中使用 _context.Set,但不能使用 InsuredBrokers.GetAll(),那是因为EF对DbContext根表达式进行了特殊处理(识别)。整个表达式翻译过程基于已知的知识,而用户定义的方法是未知的,因此不支持。 - Ivan Stoev

-1

我猜你正在尝试进行左连接。

你的查询:

var query = from customer in Customers
             join broker in InsuredBrokers
             on customer.InsertId equals broker.InsertId
             into resutGroups
            select new { Name = broker.Name, InsertId= broker.InsertId};

如果您需要针对无匹配项的条目,请使用DefaultIfEmpty

您可以参考this获取更多相关信息。


这是一个完全不同的查询。 - Gert Arnold

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接