RavenDB在Query的左侧StartsWith Variable

时间:2012-06-26 17:54:16

标签: ravendb

我有一个带有Url属性的文档集合,如下所示:

{ Url: www.test.com }  
{ Url: www.test.com/abc }  
{ Url: www.test.com/abc/xyz }

我想通过 www.test.com/abc 查询文档,以便返回所有与最新 - 包括 查询网址。即结果将返回:

{ Url: www.test.com }  
{ Url: www.test.com/abc }

以下是我为完成此操作而编写的查询。正如您所看到的,它依赖于在queryTerm上执行'Starts With',而不是在文档的属性(查询的左侧)上执行。

var queryTerm = "www.test.com/abc";
pages = session.Query<MyDocument>()
               .Where(x => queryTerm.StartsWith(x.Url));

这在Raven中不起作用;我得到'表达式不支持'错误。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

Raven似乎不支持其表达式。有趣的是,查询x => queryTerm.StartsWith(x.Url)可以分解为:

x => x.Url == queryTerm ||
     x.Url == queryTerm.Remove(queryTerm.Length - 1) ||
     x.Url == queryTerm.Remove(queryTerm.Length - 2) ||
     x.Url == queryTerm.Remove(queryTerm.Length - 3) ||
     x.Url == queryTerm.Remove(queryTerm.Length - 4) ||
     etc.

哪个可以编成:

var terms = Enumerable.Range(0, queryTerm.Length)
                      .Skip(1)
                      .Select(i => queryTerm.Remove(i));

pages = session.Query<MyDocument>()
               .Where(x => terms.Contains(x.Url));

之外,Raven也不支持Contains()。所以我编写了这个代码:

using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Linq;

namespace RavenTest
{
    [TestFixture]
    public class HowToDoBackwardsStartsWithInRaven
    {
        private readonly string[] _testUrls = new[]
            {
                "www.bad.com",
                "www.test.com",
                "www.test.com/abc",
                "www.test.com/abc/xyz"
            };

        private readonly string _queryTerm = "www.test.com/abc";

        private readonly string[] _expectedResults = new[]
            {
                "www.test.com",
                "www.test.com/abc"
            };


        [Test]
        public void FailsWithContains()
        {
            List<MyDocument> results;

            using (var store = InitStore())
            {
                LoadTestData(store);

                using (var session = store.OpenSession())
                {
                    var terms = GetAllStartingSubstrings(_queryTerm);

                    results = session.Query<MyDocument>()
                        .Where(x => terms.Contains(x.Url))
                        .ToList();
                }
            }

            Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
        }

        [Test]
        public void SucceedsWithSuperWhere()
        {
            List<MyDocument> results;

            using (var store = InitStore())
            {
                LoadTestData(store);

                using (var session = store.OpenSession())
                {
                    var terms = GetAllStartingSubstrings(_queryTerm);

                    var query = session.Query<MyDocument>()
                        .Where(x => x.Url.Length <= _queryTerm.Length);

                    foreach (var term in terms)
                        query = query.Where(x => x.Url == term ||
                                                 x.Url.Length != term.Length);

                    results = query.ToList();
                }
            }

            Assert.That(results.Select(p => p.Url), Is.EquivalentTo(_expectedResults));
        }

        private static IDocumentStore InitStore()
        {
            var store = new EmbeddableDocumentStore
                {
                    RunInMemory = true,
                };

            return store.Initialize();
        }

        private static string[] GetAllStartingSubstrings(string queryTerm)
        {
            return Enumerable.Range(0, queryTerm.Length)
                .Skip(1)
                .Select(i => queryTerm.Remove(i))
                .ToArray();
        }


        private void LoadTestData(IDocumentStore store)
        {
            using (var session = store.OpenSession())
            {
                foreach (var testUrl in _testUrls)
                    session.Store(new MyDocument {Url = testUrl});

                session.SaveChanges();
            }
        }

        public class MyDocument
        {
            public string Id { get; set; }
            public string Url { get; set; }
        }
    }
}

现在......我不知道索引的效率如何,但测试确实通过了。