2012-10-18 9 views
7

Uygulamamda, ortak bölümün sabit olduğu tüm varlıkları almak için bir sorgu oluşturduğum, ancak satır anahtarının bir sözcük aralığı içinde olması gerektiği (örneğin yalnızca başlangıç ​​satırları) uygulamasında sık karşılaşılan bir durum var.) bazı önek ile: böyle startswith olarak dize fonksiyonları sorgunun bu tür desteklenmez çünküSık kullanılan bir koşulda kullanılan Azure tablo depolama aralığı sorgusu yöntemle sarılmış

//query to get all entities in partition "KnownPartition" where RowKey starts with "Prefix_" 
CloudTableQuery<MyEntity> query = 
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName) 
    where e.PartitionKey == "KnownPartition" 
      && e.RowKey.CompareTo("Prefix_") > 0 
      && e.RowKey.CompareTo("Prefix`") <= 0 // ` is '_' + 1 
    select e).AsTableServiceQuery(); 

Ben CompareTo kullanmalıdır. Bu çalışır, ancak koşulu okumak ve tekrarlamak çok zordur. Bunu çalıştırdığınızda

public static Boolean HasPrefix(this String rowKey, String prefix) 
{ 
    return rowKey.CompareTo(prefix + '_') > 0 && rowKey.CompareTo(prefix + '`') <= 0; 
} 

CloudTableQuery<MyEntity> query = 
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName) 
    where e.PartitionKey == "KnownPartition" && e.RowKey.HasPrefix("Prefix") 
    select e).AsTableServiceQuery(); 

Fakat, bir istisna olsun: Bunun yerine bu zor okunan koşulu ile çok fazla sorgu yazma, ben daha çok "inlined" bir işlev yapmak istiyorum Benim fonksiyonum hakkında Azure desteklenmiyor. Bunu yazmanın herhangi bir yolu var mı? Her şeyden önce, çalıştığı sorgu ile tam olarak aynı koşulu kullanıyorum, sadece bir işleve sarılmış ...

cevap

10

Eğer bir işlevi koşul dışı bırakırsanız, işlev yerine bir ifade ağacı döndürmesi gerekir. bir boole değeri. LINQ sorgu sözdizimi bu destekleyecektir eğer bilmiyorum ama aşağıdaki gibi yöntem sözdizimi ile bunu yapabilirsiniz:

İşte
public static Expression<Func<MyEntity, bool>> HasPrefix(String prefix) 
{ 
    return e => e.RowKey.CompareTo(prefix + '_') > 0 && e.RowKey.CompareTo(prefix + '`') <= 0; 
} 

CloudTableQuery<MyEntity> query = 
    (from e in tableServiceContext.CreateQuery<MyEntity>(tableName) 
    where e.PartitionKey == "KnownPartition" 
    select e) 
    .Where(HasPrefix("Prefix")) 
    .AsTableServiceQuery(); 
+0

Çok güzel, bu işe yarıyor. Teşekkür ederim. Sanırım bütün ifadeyi, tutarlı bir şekilde linq sorgu sözdizimi yerine bir yöntem zinciri olarak yazabiliriz. –

+0

Oh, bu arada, umarım bu, tam bir taramayla sonuçlanmaz ... Çünkü, gerçekte devredilen varlıklar, önek koşulu için kontrol edilmişti, değil mi? –

+1

Ortaya çıkan Azure depolama isteği URI'sı: https://foo.table.core.windows.net/tablename()?$filter=((PartitionKey eq 'KnownPartition') ve (RowKey gt 'Prefix_')) ve (RowKey) le 'Önek% 60'). Yani sadece tüm şartları karşılayan satırlar iade edilecektir. Ayrıca, sorgu bölüm anahtarı ve bir dizi satır anahtarını belirttiğinden, arka uçta da tam bir tablo taraması gerekmemelidir. – Kevin

17

Kevin'in cevabın bir genellemedir. Aynı şeyi yapar, ancak David'in orijinal soruda sorduğu özel durumdan ziyade herhangi bir önek dizesi için çalışır.

public static Expression<Func<MyEntity, bool>> HasPrefix(String prefix) 
{ 
    char lastChar = prefix[prefix.Length - 1]; 
    char nextLastChar = (char)((int)lastChar + 1); 
    string nextPrefix = prefix.Substring(0, prefix.Length - 1) + nextLastChar; 

    return e => e.RowKey.CompareTo(prefix) >= 0 && e.RowKey.CompareTo(nextPrefix) < 0; 
} 
+0

Genelleştirilmiş yanıtı sağladığınız için teşekkür ederiz! MS, bu soruyu linq sorgu işlemcisine dahil etmiş olmalıydı! –