简体   繁体   English

如何使用Linq查询Azure存储表?

[英]How do I query an Azure storage table with Linq?

I'm not sure where exactly, but I've got the wrong idea somewhere with this. 我不确定到底在哪里,但我对此有错误的想法。

I'm trying to, in a first instance, query an azure storage table using linq. 我试图在第一个实例中使用linq查询azure存储表。 But I can't work out how it's done. 但我无法弄清楚它是如何完成的。 From looking at a variety of sources I have the following: 从各种来源看,我有以下几点:

List<BlogViewModel> blogs = new List<BlogViewModel>();

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("BlogConnectionString"));
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable blogTable = tableClient.GetTableReference("BlogEntries");

try
{
   TableServiceContext tableServiceContext = tableClient.GetTableServiceContext();
   TableServiceQuery<BlogEntry> query = (from blog in blogTable.CreateQuery<BlogEntry>()
   select blog).AsTableServiceQuery<BlogEntry>(tableServiceContext);
   foreach (BlogEntry blog in query)
   {
      blogs.Add(new BlogViewModel { Body = blog.Body });
   }
}
catch { }

I probably had it closer before I messed around with it. 在我搞砸之前,我可能已经把它靠近了。 Either that, or I'm misunderstanding what the TableService is. 要不然,或者我误解了TableService是什么。 The following code did work for me, but I'm trying to switch it to using Linq instead. 以下代码对我有用,但我试图将其切换为使用Linq。

List<BlogViewModel> blogs = new List<BlogViewModel>();

var storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("BlogConnectionString"));
var tableClient = storageAccount.CreateCloudTableClient();
CloudTable blogTable = tableClient.GetTableReference("BlogEntries");

TableRequestOptions reqOptions = new TableRequestOptions()
{
   MaximumExecutionTime = TimeSpan.FromSeconds(1.5),
   RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(3), 3)
};
List<BlogEntry> lists;

try
{
   var query = new TableQuery<BlogEntry>();
   lists = blogTable.ExecuteQuery(query, reqOptions).ToList();

   foreach (BlogEntry blog in lists)
   {
      blogs.Add(new BlogViewModel { Body = blog.Body });
   }
}
catch { }

I've been unable to find a good solid example anywhere of what I should be doing. 我无法在任何我应该做的事情上找到一个很好的例子。 But from what I've been reading, it does suggest using Linq is possible. 但是从我一直在阅读的内容来看,确实建议使用Linq是可能的。 Any help or pointers appreciated. 任何帮助或指针赞赏。 Thanks. 谢谢。


Slight update. 稍微更新。 The following is the syntax error I currently get on AsTableServiceQuery: 以下是我目前在AsTableServiceQuery上获得的语法错误:

'System.Linq.IQueryable' does not contain a definition for 'AsTableServiceQuery' and no extension method 'AsTableServiceQuery' accepting a first argument of type 'System.Linq.IQueryable' could be found (are you missing a using directive or an assembly reference?) 'System.Linq.IQueryable'不包含'AsTableServiceQuery'的定义,并且没有可以找到接受类型'System.Linq.IQueryable'的第一个参数的扩展方法'AsTableServiceQuery'(您是否缺少using指令或程序集引用?)

However, I don't think this reflects the real issue, I think I have just got it put together wrong, just can't find a solid example anywhere that works. 但是,我不认为这反映了真正的问题,我想我刚刚将它放在一起是错误的,只是找不到任何有效的实例。

TableServiceContext is no longer needed in the new Table Service Layer of Azure Storage Client Library. Azure存储客户端库的新表服务层中不再需要TableServiceContext。 For more information on this change, please see our blog post Announcing Storage Client Library 2.1 RTM & CTP for Windows Phone . 有关此更改的更多信息,请参阅我们的博客文章Announcing Storage Client Library 2.1 RTM和CTP for Windows Phone

Please make sure BlogEntry implements ITableEntity and then the following code should work just fine: 请确保BlogEntry实现ITableEntity ,然后以下代码应该可以正常工作:

List<BlogViewModel> blogs = new List<BlogViewModel>();

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable blogTable = tableClient.GetTableReference("BlogEntries");

try
{
    IEnumerable<BlogEntry> query = (from blog in blogTable.CreateQuery<BlogEntry>()
                                    select blog);
    foreach (BlogEntry blog in query)
    {
        blogs.Add(new BlogViewModel { Body = blog.Body });
    }
}
catch { }

My current table storage repository does this: 我当前的表存储库执行此操作:

public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression) 
{
    if (IsTableEmpty())
    {
        return Enumerable.Empty<TEntity>().AsQueryable();
    }
    else
    {
        return _cloudTable.CreateQuery<TEntity>().AsQueryable().Where(expression);
    }
}

My _ cloudTable corresponds to your blogTable . 我的_ cloudTable对应于你的blogTable

Based on previous answer, I've created extensions methods to support First, FirstOrDefault, Single and SingleOrDefault : 根据之前的回答,我创建了扩展方法来支持First, FirstOrDefault, Single and SingleOrDefault

/// <summary>
/// Provides additional Linq support for the <see cref="TableQuery{TElement}"/> class. 
/// </summary>
public static class LinqToTableQueryExtensions
{
    /// <summary>
    /// Returns the first element in a sequence.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource} to return the first element of</param>
    public static TSource First<TSource>(this TableQuery<TSource> tableQuery) where TSource : ITableEntity
    {
        return ((IEnumerable<TSource>)tableQuery.Take(1)).First();
    }

    /// <summary>
    /// Returns the first element in a sequence that satisfies a specified condition.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource} to return the first element of</param>
    /// <param name="predicate">A function to test an element for a condition.</param>
    public static TSource First<TSource>(this TableQuery<TSource> tableQuery, Expression<Func<TSource, bool>> predicate) where TSource : ITableEntity
    {
        return tableQuery.Where(predicate).Take(1).First();
    }

    /// <summary>
    /// Returns the first element of the sequence or a default value if no such element is found.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource} to return the first element of</param>
    public static TSource FirstOrDefault<TSource>(this TableQuery<TSource> tableQuery) where TSource : ITableEntity
    {
        return ((IEnumerable<TSource>)tableQuery.Take(1)).FirstOrDefault();
    }

    /// <summary>
    /// Returns the first element of the sequence that satisfies a condition or a default value if no such element is found.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource} to return the first element of</param>
    /// <param name="predicate">A function to test an element for a condition.</param>
    public static TSource FirstOrDefault<TSource>(this TableQuery<TSource> tableQuery, Expression<Func<TSource, bool>> predicate) where TSource : ITableEntity
    {
        return tableQuery.Where(predicate).Take(1).FirstOrDefault();
    }

    /// <summary>
    /// Return the only element of a sequence, and throws an exception if there is no exactly one element in the sequence.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource}> to return the single element of</param>
    /// <param name="predicate">A function to test an element for a condition.</param>
    public static TSource Single<TSource>(this TableQuery<TSource> tableQuery, Expression<Func<TSource, bool>> predicate) where TSource : ITableEntity
    {
        // Get 2 and try to get single ^^
        return tableQuery.Where(predicate).Take(2).Single();
    }

    /// <summary>
    /// Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of source.</typeparam>
    /// <param name="tableQuery">A TableQuery{TSource}> to return the single element of</param>
    /// <param name="predicate">A function to test an element for a condition.</param>
    public static TSource SingleOrDefault<TSource>(this TableQuery<TSource> tableQuery, Expression<Func<TSource, bool>> predicate) where TSource : ITableEntity
    {
        // Get 2 and try to get single ^^
        return tableQuery.Where(predicate).Take(2).SingleOrDefault();
    }
}

So you can use it like that: 所以你可以像这样使用它:

public class CustomerEntity : TableEntity { public string Email { get; set; } } 
...
var storageAccount = CloudStorageAccount.Parse( "MyStorageAccountConnectionstring");
var tableClient = storageAccount.CreateCloudTableClient();
var table = tableClient.GetTableReference("myTable");

// Linq Query with Where And First
var person = table.CreateQuery<CustomerEntity>()
    .Where(c => c.Email == "Walter1@contoso.com").First();

// Linq query that used the First() Extension method
person = table.CreateQuery<CustomerEntity>()
    .First(c => c.Email == "Walter1@contoso.com");

Here are some handy extension methods to wrap this.. (and a bonus case for ServiceBus Custom Properties keystore) 以下是一些方便的扩展方法来包装它..(以及ServiceBus Custom Properties密钥库的奖励案例)

namespace Microsoft.WindowsAzure.Storage.Table
{
    public static class CloudTableExtensions
    {
        public static TEntity GetTableEntity<TEntity>(this CloudTable cloudTable, BrokeredMessage brokeredMessage, string partitionKeyPropertyName, string rowKeyPropertyName, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
            where TEntity : ITableEntity, new()
        {
            var partitionKey = brokeredMessage.Properties[partitionKeyPropertyName] as string;
            var rowKey = brokeredMessage.Properties[rowKeyPropertyName] as string;
            return GetTableEntity<TEntity>(cloudTable, partitionKey, rowKey, requestOptions, operationContext);
        }

        public static TEntity GetTableEntity<TEntity>(this CloudTable cloudTable, string partitionKey, string rowKey, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
            where TEntity : ITableEntity, new()
        {
            var singleInstanceQuery = (Expression<Func<TEntity, bool>>)(x => x.PartitionKey == partitionKey && x.RowKey == rowKey);
            IEnumerable<TEntity> queryResults = cloudTable.ExecuteQuery(singleInstanceQuery, requestOptions, operationContext);
            return queryResults.SingleOrDefault();
        }

        public static IEnumerable<TEntity> ExecuteQuery<TEntity>(this CloudTable cloudTable, Expression<Func<TEntity, bool>> expression, TableRequestOptions requestOptions = null, OperationContext operationContext = null)
            where TEntity : ITableEntity, new()
        {
            var query = cloudTable.CreateQuery<TEntity>().Where(expression) as TableQuery<TEntity>;
            return cloudTable.ExecuteQuery(query, requestOptions, operationContext);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM