我正在使用Generic Repository模式来抽象我的EF 4.1 DbContext。我还使用服务层来查询和提交对存储库的更改。无论如何,我在这里想要实现的是允许用户在搜索栏中输入搜索短语。然后,SearchService必须查询数据库以查找其名称中包含搜索短语的任何TopLevel类别,子类别或项目。乍一看,我认为这样做很简单,但显然事情有点复杂。这是我试图做的事情:
public IList<Item> Search(string searchPhrase)
{
var result = new List<Item>();
var tmp = from c in _repository.GetQuery<TopLevelCategory>(c=>c.Children)
where c.Name.Contains(searchPhrase)
select c;
if(tmp.Count() > 0)
{
foreach (var c in tmp)
{
var children = c.Children;
foreach (var childCategory in children)
{
result.Concat(childCategory.Items);
}
}
}
var tmp2 = from c in _repository.GetQuery<ChildCategory>(c=>c.Items)
where c.Name.Contains(searchPhrase)
select c;
if(tmp.Count() > 0)
{
foreach (var childCategory in tmp2)
{
result.Concat(childCategory.Items);
}
}
var tmp3 = from c in _repository.GetQuery<Item>()
where c.Title.Contains(searchPhrase)
select c;
if(tmp3.Count() > 0)
{
result.Concat(tmp3);
}
return result;
}
}
我知道这看起来很丑陋并搞砸了,但我只是试一试,看看它是否会返回正确的结果。好吧它没有,它抛出了以下异常:
异常详细信息: System.InvalidOperationException: 已经有一个开放的DataReader 与此命令相关联 必须先关闭。
Source:
Line 31: foreach (var childCategory in children)
Line 32: {
Line 33: result.Concat(childCategory.Items);
Line 34: }
所以无论如何,必须有一个更聪明的方法来做这个......有什么建议吗?
答案 0 :(得分:2)
例外情况表明,您已打开DataReader以使用其子级加载顶级类别,但是您在内部foreach循环中触发延迟加载。这需要另一个DataReader来打开和读取延迟加载的项目:
// Iterate top level categories => fist openned DataReader
foreach (var c in tmp)
{
// Child category is eager loaded
var children = c.Children;
foreach (var childCategory in children)
{
// Items are not eager loaded => trigger lazy loading and open new DataReader
result.Concat(childCategory.Items);
}
}
要解决此问题,您必须修改连接字符串并添加MARS支持MultipleActiveResultSets=true
。 MARS至少得到SQL Server 2005和2008的支持。避免这种情况的另一种方法是热切的加载项。
这看起来更像是在数据库级别进行全文搜索的任务。
答案 1 :(得分:0)