使用GenericRepository模式和SearchService搜索功能

时间:2011-04-25 11:50:10

标签: asp.net-mvc entity-framework search repository-pattern entity-framework-4.1

我正在使用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:          }

所以无论如何,必须有一个更聪明的方法来做这个......有什么建议吗?

2 个答案:

答案 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)

您获得的错误可能是由于MARS。您只需要启用多个活动结果集(MARS),只需在连接字符串中添加“MultipleActiveResultSets = True”即可。查看here


  1. 您可以创建一个连接TopLevel,Childlevel和items中的名称的视图。然后将此视图公开为实体。请记住,EF会在设计师尝试确定ID字段时遇到问题。
  2. 如果您认为需要更好的\ strong查询功能,可以查看lucene