Как запросить таблицу хранения Azure с Linq?

Я не уверен, где именно, но у меня есть неправильная идея где-то с этим.

Я пытаюсь в первом случае запросить таблицу хранения azure с помощью linq. Но я не могу понять, как это делается. От взгляда на различные источники я имею следующее:

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 { }

Я, наверное, подобрал его ближе, прежде чем я с ним столкнулся. Либо это, либо я не понимаю, что такое TableService. Следующий код действительно работал у меня, но я пытаюсь переключить его на использование 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 { }

Я не смог найти хороший хороший пример, где бы я ни делал. Но из того, что я читал, это предполагает использование Linq. Любая помощь или указатели оценили. Спасибо.


Небольшое обновление. Ниже приведена синтаксическая ошибка, которую я сейчас получаю в AsTableServiceQuery:

'System.Linq.IQueryable' не содержит определения для "AsTableServiceQuery" и не может быть найден метод расширения "AsTableServiceQuery", принимающий первый аргумент типа "System.Linq.IQueryable" (вам не хватает директивы using или ссылка на сборку?)

Тем не менее, я не думаю, что это отражает реальную проблему, я думаю, что я только что собрал ее неправильно, просто не могу найти убедительный пример где-нибудь, что работает.

Ответ 1

TableServiceContext больше не требуется в новом уровне службы таблиц клиентской библиотеки хранилища Azure. Дополнительную информацию об этом изменении см. В нашем блоге " Объявление о клиентской библиотеке хранилища 2.1 RTM и CTP для Windows Phone".

Убедитесь, что 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 { }

Ответ 2

Мой текущий репозиторий хранилища таблиц делает это:

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 соответствует вашему blogTable.

Ответ 3

Основываясь на предыдущем ответе, я создал методы расширения для поддержки 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();
    }
}

Итак, вы можете использовать его так:

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 == "[email protected]").First();

// Linq query that used the First() Extension method
person = table.CreateQuery<CustomerEntity>()
    .First(c => c.Email == "[email protected]");

Ответ 4

Вот несколько удобных методов расширения, чтобы обернуть это. (и бонусный случай для кэширования пользовательских свойств ServiceBus)

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);
        }
    }
}