2014-04-30 13 views
12

Nie jestem pewien, gdzie dokładnie, ale mam gdzieś ten pomysł.Jak przesłać zapytanie do tabeli pamięci masowej Azure za pomocą Linq?

Próbuję, w pierwszej kolejności, kwerendy tabeli przechowywania lazuru za pomocą linq. Ale nie mogę zrozumieć, jak to się robi. Spoglądając na różne źródła, mam następujące:

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

Prawdopodobnie miałem go bliżej, zanim się z nim pobrałem. Albo to, albo nie rozumiem, czym jest TableService. Poniższy kod pracował dla mnie, ale staram się go zmienić na 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 { } 

Nie udało mi się znaleźć dobrego przykładu z tego, co powinienem robić. Ale z tego, co czytałem, wynika, że ​​użycie Linq jest możliwe. Każda pomoc lub wskazówki zostały docenione. Dzięki.


Nieznaczna aktualizacja. Poniżej znajduje się błąd składniowy, który aktualnie dostaję w AsTableServiceQuery:

"System.Linq.IQueryable" nie zawiera definicji "AsTableServiceQuery" i nie ma metody rozszerzenia "AsTableServiceQuery" akceptującej pierwszy argument typu "System.Linq. IQueryable "można znaleźć (czy brakuje Ci dyrektywy dotyczącej użycia lub odniesienia do zespołu?)

Jednak nie sądzę, aby odzwierciedlało to prawdziwy problem, myślę, że właśnie to zrobiłem źle, po prostu nie mogę znajdź solidny przykład w dowolnym miejscu, który działa.

+0

co dokładnie się dzieje? otrzymujesz komunikaty o błędach? brak danych? – Igorek

+0

@Igorek Przepraszam, zaktualizowałem z błędem. Jednak nie sądzę, aby kod był wystarczająco zbliżony do tego, jak powinien wyglądać błąd, aby naprawdę cokolwiek znaczyć. – AndrewPolland

Odpowiedz

23

Obiekt TableServiceContext nie jest już potrzebny w nowej warstwie usług tabelowych biblioteki klienta Azure Storage. Więcej informacji na temat tej zmiany można znaleźć w naszym poście na blogu Announcing Storage Client Library 2.1 RTM & CTP for Windows Phone.

Upewnij BlogEntry realizuje ITableEntity a następnie następujący kod powinien działać dobrze:

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

Idealny. Dokładnie przykład, którego szukałem. Dziękuję Ci. – AndrewPolland

+0

CreateQuery nie jest obsługiwany w systemie Windows Phone. – Senkwe

+0

Co jeśli nasz podmiot dziedziczy już z innej klasy? Czy jest jakaś inna opcja do wykonania zapytania? – Paul

13

Mój obecny repozytorium do przechowywania tabeli robi to:

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 odpowiada Twoim blogTable.

+0

To zapisz mi dzień :-) Nice! –

+0

Dziękuję bardzo, również uratowałem mój dzień! –

1

podstawie poprzedniej odpowiedzi, mam utworzone metod rozszerzeń wspierać 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(); 
    } 
} 

Tak możesz go użyć w następujący sposób:

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]"); 
+0

Jakie jest zamierzone użycie tego? 'TableQuery' nie zawiera żadnych danych i musi być wykonane przy użyciu' CloudTable.Execute (query) 'lub podobnej metody. 'First *()' & 'Single *()' zwróci zapytania, których nie można przekazać do 'Execute()'. – JoeBrockhaus

+0

@JoeBrockhaus, Edytowałem swoją odpowiedź, aby pokazać, jak korzystać z tych metod rozszerzenia. – Thomas

+0

Widzę, słownictwo w metodzie CreateQuery sprawia, że ​​wydaje się, że musisz wyraźnie wywołać jedną z metod Execute. To dość denerwujące tylko część interfejsu IQueryable jest obsługiwana, i nie jest jasne, które w czasie kompilacji: - / – JoeBrockhaus

0

Oto kilka przydatnych metod przedłużania zawinąć to .. (a sprawa premii dla Properties ServiceBus Niestandardowe kluczy)

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); 
     } 
    } 
} 
Powiązane problemy