在哪里使用Azure DocumentDB(CosmosDB).Net SDK

时间:2017-06-19 17:53:22

标签: azure azure-cosmosdb

看过this question我不确定为什么我的DocDb实例的以下代码无效

var userApps = _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
        new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
    .ToList()
    .Select(s => (string)s.appId);
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
        new SqlQuerySpec(@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN (@userApps)", (@"@userApps", userApps.ToArray()).ToSqlParameters()),
        new FeedOptions { EnableCrossPartitionQuery = true })
    .AsDocumentQuery();

当我执行此操作时,虽然我知道数据应该返回结果集,但每次都会返回空白。

到目前为止的疑难解答

.Select()

的变体

string.Join的字符串返回到以逗号分隔的列表中。

例如:

var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
        new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameters()))
    .ToList()
    .Select(s => $@"'{s.appId}'");

不要封装IN参数

在查询思想中删除参数规范周围的()可能是SqlParameter规范正在进行数组规范吗?

例如:@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN @userApps"

结束投掷&#34;语法错误,&#39; @ userApps&#39;附近的语法不正确。&#34;

通过Azure门户查询验证

执行此代码应运行的(预期)SQL。

我没有问题地收回我的预期结果(即:我知道这些查询的结果集已经写好了)。

查询1的调试器输出

AppIds 从查询1回来。

不满意的解决方法

将查询2更改为进行参数化。而是将逗号分隔的查询1中的ID列表注入其中:

var userApps = string.Join(@",", _docs.CreateDocumentQuery(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.USER_APPS),
        new SqlQuerySpec(@"SELECT r.appId FROM ROOT r WHERE r.userId = @userId", (@"@userId", userId).ToSqlParameter()))
    .ToList()
    .Select(s => $@"'{s.appId}'"));
var query = _docs.CreateDocumentQuery<Document>(UriFactory.CreateDocumentCollectionUri(Constants.Databases.Applications.ID, Constants.Databases.Applications.Collections.APP_DEFINITIONS),
        new SqlQuerySpec($@"SELECT r.id, r.appName FROM ROOT r WHERE r.appId IN ({userApps})"),
        new FeedOptions { EnableCrossPartitionQuery = true })
    .AsDocumentQuery();

完美的工作,但我不会接受它作为这个问题的答案,因为它违背了几十年的SQL最佳实践,坦率地说,不应该成为一个解决方案。

这是我的ToSqlParameters()扩展方法,以防它成为罪魁祸首(这可以在我使用它的其他地方工作。但是数组可能需要特殊的东西吗?):

public static SqlParameterCollection ToSqlParameters(this (string, object) parmDef) => new SqlParameterCollection(new[] { new SqlParameter(parmDef.Item1, parmDef.Item2) });

谢谢!

1 个答案:

答案 0 :(得分:4)

如果您使用参数化的IN列表,那么在扩展参数时它将被视为单个值。

例如,对于此查询: SELECT * FROM r WHERE r.item IN(@items) @items被定义为&#34; [&#39; val1&#39;,&#39; val2&#39;,&#39; val3&#39;]&#34;那么查询将被解释为: SELECT * FROM r WHERE r.item IN([&#39; val1&#39;,&#39; val2&#39;,&#39; val3&#39;]) 这基本上意味着您将r.item与单个值进行比较,该值是三个元素的数组(即相当于r.item = [&#39; val1&#39;,&#39; val2&#39; ,&#39; val3&#39;])。

要与多个项目进行比较,您需要为每个值使用一个参数。像这样的东西: SELECT * FROM r WHERE r.item IN(@ val1,@ val2,@ val3])

编写此查询的一种更方便的方法是使用ARRAY_CONTAINS,并将项数组作为单个参数传递。所以上面的查询将这样写: SELECT * FROM r WHERE ARRAY_CONTAINS(@items,r.item)