C# 在EntityFramework中使用SqlQuery组成一个真正的IQueryable
有没有办法让SqlQuery或任何其他sql执行方法组成一个模型对象,并允许像Include这样的方法工作?我正在这样做(其中view_products是一个SQL表函数): 这会给我一个DbRawSqlQuery。这是我不能“包含”的,因为在DbRawSqlQuery上不能这样做。因此,我在末尾添加了一个AsQueryable,如:C# 在EntityFramework中使用SqlQuery组成一个真正的IQueryable,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,有没有办法让SqlQuery或任何其他sql执行方法组成一个模型对象,并允许像Include这样的方法工作?我正在这样做(其中view_products是一个SQL表函数): 这会给我一个DbRawSqlQuery。这是我不能“包含”的,因为在DbRawSqlQuery上不能这样做。因此,我在末尾添加了一个AsQueryable,如: var p = context.SqlQuery<Product>("select * from view_products(@param1)", n
var p = context.SqlQuery<Product>("select * from view_products(@param1)", new SqlParameter("param1", "somevalue")).AsQueryable<Product>();
var p=context.SqlQuery(“从视图中选择*产品(@param1)”,新的SqlParameter(“param1”,“somevalue”)).AsQueryable();
但是,我知道这确实给了我一个IEnumerable,所以.Include不会产生任何结果
我正在寻找另一种方法的建议,从SQL函数中获取产品,然后加载相关的库存对象,这样我就有了一个对象图。谢谢
SqlQuery
带来了一些我还没有意识到的问题
不包括
您正确地解释了为什么将IEnumerable
转换为IQueryable
后,Include
没有任何效果Include
扩展了一个表达式,而IEnumerable
没有表达式(并且在将其转换为IQueryable
后不会神奇地得到一个表达式)
没有连接就没有延迟加载
因此,您的产品
列表没有附加到上下文,并且不能延迟加载。您必须将产品
明确地附加到上下文中(例如,通过将其状态设置为未更改
),使其延迟加载
这是我刚刚发现的,很奇怪。实体被物化为代理对象,但与通过DbSet.AsNoTracking()
获取的分离实体相反,它们不显示延迟加载。我认为这是一个错误,我报告了它
但是延迟加载会导致n+1查询反模式:分别获取每个产品的库存对象的查询。所以这不是获取对象图的最佳方法
没有关系修复
因此,您真正想要的是一次性加载属于这些产品的所有库存对象,并让关系修复完成其工作(即EF自动填充所有Product.Inventory
collections):
…其中,productID
是p
中的产品ID列表
但是关系修复只适用于连接的实体,所以同样,您必须显式地将它们的状态更改为未更改。如果你这么做,你就准备好了。。。除非你不是
同样,通过DbSet.AsNoTracking()
获取的分离实体也有区别。后者响应关系修复,来自SqlQuery
的则不响应
(而是)详细的解决方案
所以剩下的是:加载上面显示的相关库存
对象,并填充产品。库存
集合:
var query = from product in p
join inv context.Inventories.Local
on product.ProductId equals inv.ProductId
into inventories
select new { product, inventories }
foreach(var anon in query)
{
anon.product.Inventories = anon.inventories.ToList();
}
当然,这一切都很不令人满意。恰到好处地使用where子句2将查询连接到两个表中。并从联接表中选择*作为导航属性name@Brandon赛德尔,这会让我得到我想要的数据,但不会填充对象图。我认为这是目前所能期望的最好结果。我将注意力转向摆脱SQL表函数,并在EF查询中完成这一切。谢谢你的建议!
var p = context.SqlQuery<Product>("select * from view_products(@param1)", new SqlParameter("param1", "somevalue")).AsQueryable<Product>();
context.Inventories.Where(i => productIds.Contains(i.ProductId)).Load();
var query = from product in p
join inv context.Inventories.Local
on product.ProductId equals inv.ProductId
into inventories
select new { product, inventories }
foreach(var anon in query)
{
anon.product.Inventories = anon.inventories.ToList();
}