RavenDB - 防止查询错误异常

时间:2015-10-02 05:17:01

标签: ravendb

我正在尝试在应用程序中实现一些自定义搜索,允许用户键入某些字段和术语并查询结果;例如,有一个文本框,他们可以输入... Name: Stacey并运行一些代码。

如果他们给它一个有效的名字,那就行得很好。但是,如果他们给它提供的信息无法找到,我会得到一个例外,我无法弄清楚如何阻止它。 try似乎也不起作用;代码并不复杂,但有点分手。

基本上,这是在从控制器方法接收零个或两个字符串后运行的。第一个字符串是字段,第二个字符串是要查询的值。如果我给它有效的输入,它工作正常;但是其他任何事情都会导致程序崩溃。我能做些什么吗?

冗长的回调过程是因为每个控制器方法需要对结果做出不同的反应,但这与此问题无关。

    private JsonResult JsonDataFromDataSourceRequest<T, TIndexCreator>
        ([DataSourceRequest] DataSourceRequest request,
        Func<IDocumentQuery<T>, string, string, IDocumentQuery<T>> search,
        Func<IDocumentQuery<T>, IDocumentQuery<T>> sort)
        where T : IHasName
        where TIndexCreator : Raven.Client.Indexes.AbstractIndexCreationTask, new() {
        RavenQueryStatistics statistics;

        var query = RavenSession
            .Advanced.DocumentQuery<T, TIndexCreator>()
            .WhereEquals("collection", typeof(T).RavenCollection())
            .WaitForNonStaleResultsAsOfNow()
            .Statistics(out statistics); // output our query statistics

        // we can accept a sorting system, or additional query options here
        if (sort != null)
            query = sort(query);

        if (request.Filters != null) {
            if (request.Filters.Any()) {
                var filters = request.Filters.ToFilters();

                // determine the field/term to search by
                var name = filters.Count > 0 ? filters[0].Value.ToString() : null;
                var field = filters.Count > 0 ? filters[0].Member.ToString() : "Name";

                if (name != null && !String.IsNullOrEmpty(name)) {
                    query = query.AndAlso().Search(field, name);
                }
            }
        }

        var results = query
            .OrderBy(n => n.Name)
            .Skip((request.Page - 1) * request.PageSize)
            .Take(request.PageSize)
            .ToList();

        var totalResults = statistics.TotalResults;

        return Json(new { data = results, total = totalResults });
    }

更新

System.InvalidOperationException

抛出的异常是System.InvalidOperationException。当我深入研究调试器时,发送到Raven的实际查询的形式为;

{collection:users AND DisplayName: ( Stacey)}

这是一种混合包;让我解释一下。

collection存在是因为此索引用于许多不同的对象,但许多(如果不是全部)对象共享几个相似的字段。将集合作为查询的一部分而不是试图找到在Type调用中使用Query<T>的方法似乎更简单。

是否可以保持灵活性并为查询提供特定的TModel来查询?我想避免制作几十个重复索引。

当用户尝试查找不在被检查对象类型的字段时,似乎会发生这种情况。

换句话说,即使Owner被编入索引,如果用户针对查找Owner: Ciel的页面键入Users执行此操作不Owner字段(但许多其他类都有),它会抛出此错误。如果他们试图输入一个没有编入索引的字段,它就会这样做。

如果查询失败,是否可以返回 nothing

以下是我正在使用的索引。也许有一种更简单的方法可以在没有collection字段的情况下做到这一点,但是我并没有意识到这一点(但我仍然缺乏经验)。 有近28个不同的页面,每个页面都有搜索功能。一些实体之间存在许多类似的字段,因此制作28个不同的索引似乎毫无意义。

public class EntityByName : AbstractIndexCreationTask {
    public override IndexDefinition CreateIndexDefinition() {
        return new IndexDefinition {
            Map = @"
                from doc in docs 
                let collection = doc[""@metadata""][""Raven-Entity-Name""] 
                select new { 
                    doc.Id, 
                    doc.Name, 
                    doc.Owner,  
                    doc.Group,
                    doc.Email,
                    Tags = doc.Tags.Select( r => r.Name ),
                    collection 
                };",
            Indexes ={
                {"Id", FieldIndexing.Analyzed},
                {"Name", FieldIndexing.Analyzed},
                {"Owner", FieldIndexing.Analyzed},
                {"Tags", FieldIndexing.Analyzed},
                {"Group", FieldIndexing.Analyzed},
                {"Email", FieldIndexing.Analyzed}
            }
        };
    }

    public override string IndexName {
        get { return "Raven/DocumentsByEntity"; }
    }
}

异常消息

这是一个完整的异常消息。

Url: "/databases/dev-isolated/indexes/Raven/DocumentsByEntity?&query=collection%3Ausers%20AND%20Number%3A%28%203%29&pageSize=5&sort=Name&SortHint-collection=String&SortHint-Name=String&cutOff=2015-10-02T15%3A12%3A31.5784892Z&waitForNonStaleResultsAsOfNow=true"

System.ArgumentException: The field 'DisplayName' is not indexed, cannot query on fields that are not indexed
   at Raven.Database.Indexing.Index.AssertQueryDoesNotContainFieldsThatAreNotIndexed(IndexQuery indexQuery, AbstractViewGenerator viewGenerator) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Indexing\Index.cs:line 1130
   at Raven.Database.Indexing.Index.IndexQueryOperation.<Query>d__5a.MoveNext() in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Indexing\Index.cs:line 1252
   at Raven.Database.Util.ActiveEnumerable`1..ctor(IEnumerable`1 enumerable) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Util\ActiveEnumerable.cs:line 16
   at Raven.Database.Actions.QueryActions.DatabaseQueryOperation.Init() in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Actions\QueryActions.cs:line 245
   at Raven.Database.Actions.QueryActions.<>c__DisplayClasse.<Query>b__a(IStorageActionsAccessor accessor) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Actions\QueryActions.cs:line 118
   at Raven.Storage.Esent.TransactionalStorage.ExecuteBatch(Action`1 action, EsentTransactionContext transactionContext) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Storage\Esent\TransactionalStorage.cs:line 843
   at Raven.Storage.Esent.TransactionalStorage.Batch(Action`1 action) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Storage\Esent\TransactionalStorage.cs:line 807
   at Raven.Database.Actions.QueryActions.Query(String index, IndexQuery query, CancellationToken externalCancellationToken) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Actions\QueryActions.cs:line 108
   at Raven.Database.Server.Controllers.IndexController.PerformQueryAgainstExistingIndex(String index, IndexQuery indexQuery, Etag& indexEtag, HttpResponseMessage msg, CancellationToken token) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Server\Controllers\IndexController.cs:line 625
   at Raven.Database.Server.Controllers.IndexController.ExecuteQuery(String index, Etag& indexEtag, HttpResponseMessage msg, CancellationToken token) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Server\Controllers\IndexController.cs:line 570
   at Raven.Database.Server.Controllers.IndexController.GetIndexQueryResult(String index, CancellationToken token) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Server\Controllers\IndexController.cs:line 541
   at Raven.Database.Server.Controllers.IndexController.IndexGet(String id) in c:\Builds\RavenDB-Stable-3.0\Raven.Database\Server\Controllers\IndexController.cs:line 182
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()

修复

我做了相应的更改,这是该方法的最终结果;

    private JsonResult JsonDataFromDataSourceRequest<T, TIndexCreator>
        ([DataSourceRequest] DataSourceRequest request,
        Func<IDocumentQuery<T>, string, string, IDocumentQuery<T>> search,
        Func<IDocumentQuery<T>, IDocumentQuery<T>> sort)
        where T : IHasName
        where TIndexCreator : Raven.Client.Indexes.AbstractIndexCreationTask, new() {

        try {

            // we need to be able to catch some query statistics to make sure that the
            // grid view is complete and accurate, with paging
            RavenQueryStatistics statistics;

            // try to query the items listing as quickly as we can, getting only the
            // page we want out of it
            var query = RavenSession
                .Advanced.DocumentQuery<T, TIndexCreator>()
                .WhereEquals("collection", typeof(T).RavenCollection())
                .WaitForNonStaleResultsAsOfNow()
                .Statistics(out statistics); // output our query statistics

            // we can accept a sorting system, or additional query options here
            if (sort != null)
                query = sort(query);

            // deserialize the contents of the kendo grid filter
            if (request.Filters != null) {
                if (request.Filters.Any()) {
                    var filters = request.Filters.ToFilters();

                    var name = filters.Count > 0 ? filters[0].Value.ToString() : null;
                    var field = filters.Count > 0 ? filters[0].Member.ToString() : "Name";

                    if (name != null && !String.IsNullOrEmpty(name)) {
                        query = search(query, field, name);
                    }
                }
            }

            // finish constructing the items query
            var results = query
                .OrderBy(n => n.Name)
                .Skip((request.Page - 1) * request.PageSize)
                .Take(request.PageSize)
                .ToList();

            var totalResults = statistics.TotalResults;

            return Json(new { data = results, total = totalResults, errors = "" });
        }
        catch {

            // the user tried to ask for something
            // that doesn't exist, or a field that
            // cannot be queried
            var results = new List<T>();

            // total results is always 0 on an error
            var totalResults = 0;

            var errors = new List<string> {
                "You have attempted to query an invalid field, or given an inappropriate value."
            };

            return Json(new { data = results, total = totalResults, errors = errors });
        }
    }

1 个答案:

答案 0 :(得分:2)

错误很明显:

The field 'DisplayName' is not indexed, cannot query on fields that are not indexed