C# 修改EF结果并序列化到客户端
我正在从数据库中获取密钥列表,并根据特定条件对其进行修改。该列表被序列化为对AJAX调用的响应 但是,当我在此过程中多次修改列表时,Resharper告诉我“C# 修改EF结果并序列化到客户端,c#,asp.net,entity-framework,C#,Asp.net,Entity Framework,我正在从数据库中获取密钥列表,并根据特定条件对其进行修改。该列表被序列化为对AJAX调用的响应 但是,当我在此过程中多次修改列表时,Resharper告诉我“ienumerable的可能多重枚举” 我是否应该在涉及列表的所有行上使用ToList() 请推荐一种合适的方法: IEnumerable<decimal> foo = databaseContext.Foo.Select(f=>f.Key); if(something) foo = foo.Where(f=&g
ienumerable的可能多重枚举”
我是否应该在涉及列表的所有行上使用ToList()
请推荐一种合适的方法:
IEnumerable<decimal> foo = databaseContext.Foo.Select(f=>f.Key);
if(something)
foo = foo.Where(f=>f.Bar > 5);
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.ToList() });
HttpContext.Current.Response.Write(json);
IEnumerable foo=databaseContext.foo.Select(f=>f.Key);
如果(某物)
foo=foo.Where(f=>f.Bar>5);
如果(某物)
foo=foo.Where(f=>f.Bar>15);
var json=newJavaScriptSerializer.Serialize(new{fooKeys=foo.ToList()});
HttpContext.Current.Response.Write(json);
我认为您的代码不正确,当您在对象集上进行选择时,您会得到一个查询表。我认为您无法将查询表分配给IEnumerable
在使用IQueryable ToList()方法之前,queryAble实际上不会对db执行请求
因此,首先应该定义查询,然后使用ToList()方法对db执行查询,该方法将返回您的类型列表
你应该把你的代码重新排列成这样
var resultSetInMemory = new List<decimal>();
if(somethink) {
resultSetInMemory = databaseContext.Foo
.Where(f=>f.Bar > 5)
.Select(f.key)
.ToList();
}
if(somethingElse) {
resultSetInMemory = databaseContext.Foo
.Where(f=>f.Bar > 15)
.Select(f.key)
.ToList();
}
var json = new JavaScriptSerializer.Serialize(new { fooKeys = resultSetInMemory });
var resultSetInMemory=new List();
如果(想){
resultsteinmemory=databaseContext.Foo
.其中(f=>f.Bar>5)
.选择(f键)
.ToList();
}
如果(某物){
resultsteinmemory=databaseContext.Foo
.其中(f=>f.Bar>15)
.选择(f键)
.ToList();
}
var json=new JavaScriptSerializer.Serialize(新的{fooKeys=resultsteinmemory});
这是我经常看到的方法。希望这对你也有帮助。Resharper的分析是正确的。您可能会多次执行查询。问题出在您的第一行:
IEnumerable<decimal> foo = databaseContext.Foo.Select(f=>f.Key);
另外,我猜这是您的疏忽,但是foo
是decimal
的可枚举项,但是您过滤了Bar
属性。这甚至不会编译
编辑:我已冒昧地修改了您的原始代码(第一部分),以向您显示明细:
// databaseContext.Foo is a (presumably) DbSet<Foo> that implements
// IQueryable<Foo>. Because the variable foo is set to be an IEnumerable<Foo>
// and that IQueryable<Foo> implements IEnumerable<Foo> by calling
// as AsEnumerable(), any further manipulation of the IEnumerable<Foo>
// will be with LINQ to Object and not Linq to SQL (with Entity Framework)
IEnumerable<Foo> foo = databaseContext.Foo;
// Because of the previous point, this will potentially execute the query
if(something)
foo = foo.Where(f=>f.Bar > 5);
// And this will as well
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
// And ToList() will definitely execute it.
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.Select(f => f.Key).ToList() });
HttpContext.Current.Response.Write(json);
//databaseContext.Foo是(大概)一个实现
//易读的。因为变量foo被设置为IEnumerable
//IQueryable通过调用
//作为AsEnumerable(),对IEnumerable的任何进一步操作
//将使用LINQ到对象,而不是LINQ到SQL(使用实体框架)
IEnumerable foo=databaseContext.foo;
//由于前面的一点,这可能会执行查询
如果(某物)
foo=foo.Where(f=>f.Bar>5);
//这也会
如果(某物)
foo=foo.Where(f=>f.Bar>15);
//ToList()肯定会执行它。
var json=newJavaScriptSerializer.Serialize(new{fooKeys=foo.Select(f=>f.Key.ToList());
HttpContext.Current.Response.Write(json);
现在,如果您改为这样做:
// DbSet<Foo> will create an IQueryable<Foo>. An Entity Framework IQueryProvider
// will compile this to an SQL when we want to materialize the query
IQueryable<Foo> foo = databaseContext.Foo;
// Now, if this is hit, it's fine because IQueryable.Where returns an IQueryable
// of the same type. We still live in the
if(something)
foo = foo.Where(f=>f.Bar > 5);
// Same point as before. foo is still an IQueryable<Foo> and the materialization
// is not provoked yet.
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
// Here, foo.Select() will return an IQueryable<decimal> (or whatever the type
// of the Foo.Key property is) and then ToList() will get the IEnumerable<decimal>
// version. At that point, any further manipulation is done through Linq to Object
// but the query won't be sent to the database until it is iterated (ie
// the IEnumerable<decimal>.GetEnumerator() is called). The IEnumerable<decimal>
// version of the will be passed to the List<T>(IEnumerable<T>) constructor
// which will iterate through the Enumerable with the GetEnumerator method.
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.Select(f => f.Key).ToList() });
HttpContext.Current.Response.Write(json);
//DbSet将创建IQueryable。实体框架提供程序
//当我们想要具体化查询时,会将其编译为SQL
IQueryable foo=databaseContext.foo;
//现在,如果这个被命中,这是好的,因为IQueryable。哪里返回IQueryable
//同类的。我们仍然住在城市里
如果(某物)
foo=foo.Where(f=>f.Bar>5);
//和以前一样。foo仍然是一个IQueryable和物化
//还没有被激怒。
如果(某物)
foo=foo.Where(f=>f.Bar>15);
//这里,foo.Select()将返回IQueryable(或任何类型)
//Key属性的值为),然后ToList()将获得IEnumerable
//版本。在这一点上,任何进一步的操作都是通过Linq来完成的
//但是查询在被迭代之前不会被发送到数据库(即
//调用IEnumerable.GetEnumerator()。数不清的
//的版本将传递给列表(IEnumerable)构造函数
//它将使用GetEnumerator方法遍历可枚举项。
var json=newJavaScriptSerializer.Serialize(new{fooKeys=foo.Select(f=>f.Key.ToList());
HttpContext.Current.Response.Write(json);
如您所见,通过在开始和结束时使用IQueryable
,直到ToList()
,您仍将生活在IQueryable
延迟查询执行世界中,Resharper将停止抱怨。因此,您建议对数据库执行两个查询,同时丢失第一个查询的结果,甚至得不到与他应该得到的相同的结果?啊,不,这不太好。你是对的。更好的方法是在函数末尾说ToList(),通常在这里返回结果。谢谢您的输入。从一开始就将其作为一个通用列表,并在每种情况下使用Where().Tolist()
是否是一个坏主意?是的。ToList()将执行一个查询。第一个将从数据库执行,其余的都将创建中间列表。当你对数据库的查询很好的时候,你应该考虑保持你的可查询性,所以你建议我做一个<代码>可查询的< /COD>,而不是上面的代码> iQueabd。这难道不会引起与resharper现在警告我的问题相同的问题吗?@Johan IQueryable在任何时候都不会列举。一份不可胜数的遗嘱。对不起,我没听懂。如果像我的示例中那样使用IEnumerable
,问题仍然存在。你能举例说明你建议的方法吗?
// DbSet<Foo> will create an IQueryable<Foo>. An Entity Framework IQueryProvider
// will compile this to an SQL when we want to materialize the query
IQueryable<Foo> foo = databaseContext.Foo;
// Now, if this is hit, it's fine because IQueryable.Where returns an IQueryable
// of the same type. We still live in the
if(something)
foo = foo.Where(f=>f.Bar > 5);
// Same point as before. foo is still an IQueryable<Foo> and the materialization
// is not provoked yet.
if(somethingElse)
foo = foo.Where(f=>f.Bar > 15);
// Here, foo.Select() will return an IQueryable<decimal> (or whatever the type
// of the Foo.Key property is) and then ToList() will get the IEnumerable<decimal>
// version. At that point, any further manipulation is done through Linq to Object
// but the query won't be sent to the database until it is iterated (ie
// the IEnumerable<decimal>.GetEnumerator() is called). The IEnumerable<decimal>
// version of the will be passed to the List<T>(IEnumerable<T>) constructor
// which will iterate through the Enumerable with the GetEnumerator method.
var json = new JavaScriptSerializer.Serialize(new { fooKeys = foo.Select(f => f.Key).ToList() });
HttpContext.Current.Response.Write(json);