2

次のような Url プロパティを持つドキュメントのコレクションがあります。

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

www.test.com/abcを使用してドキュメントをクエリしたいので、クエリ URLを含むすべての URL に一致するすべてのドキュメントが返されます。つまり、結果は次のように返されます。

{ 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 では機能しません。「式の型はサポートされていません」というエラーが表示されます。何か案は?

4

1 に答える 1

1

レイヴンは、その表現でそれをサポートしているようには見えません. 興味深いことに、クエリ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));

ただし、レイヴンもそのようにはサポートしていません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; }
        }
    }
}

さて...インデックス作成がどれほど効率的かはわかりませんが、テストは成功します。

于 2012-06-27T04:16:15.940 に答える