2015-10-16 49 views
0

我有一個大型的應用程序,有30多個項目,目前使用的是IRepository和POCO實體。我想知道是否有辦法使用表存儲而不必實施ITableEntity。我不想將Azure存儲塊塊包導入每個項目,並將所有實體更改爲使用ITableEntity。您可以將Azure表存儲IQueryable(table.CreateQuery())作爲POCO公開嗎?

實體Adapater

我知道,有可能創建一個實體適配器(例如低於)讀取或寫入一個單獨的實體時工作得很好。但是當我嘗試通過table.CreateQuery()公開IQueryable時,我一直無法獲得這個工作。

public class AzureEntity 
{ 
    public Guid Id { get; set; } 
    public string PartitionKey { get; set; } 
    public string RowKey { get; set; } 
    public DateTimeOffset Timestamp { get; set; } 
    public string ETag { get; set; } 
} 

internal class AzureStorageEntityAdapter<T> : ITableEntity where T : AzureEntity, new() 
{ 
    #region Properties 
    /// <summary> 
    /// Gets or sets the entity's partition key 
    /// </summary> 
    public string PartitionKey 
    { 
     get { return InnerObject.PartitionKey; } 
     set { InnerObject.PartitionKey = value; } 
    } 

    /// <summary> 
    /// Gets or sets the entity's row key. 
    /// </summary> 
    public string RowKey 
    { 
     get { return InnerObject.RowKey; } 
     set { InnerObject.RowKey = value; } 
    } 

    /// <summary> 
    /// Gets or sets the entity's Timestamp. 
    /// </summary> 
    public DateTimeOffset Timestamp 
    { 
     get { return InnerObject.Timestamp; } 
     set { InnerObject.Timestamp = value; } 
    } 

    /// <summary> 
    /// Gets or sets the entity's current ETag. 
    /// Set this value to '*' in order to blindly overwrite an entity as part of an update operation. 
    /// </summary> 
    public string ETag 
    { 
     get { return InnerObject.ETag; } 
     set { InnerObject.ETag = value; } 
    } 

    /// <summary> 
    /// Place holder for the original entity 
    /// </summary> 
    public T InnerObject { get; set; } 
    #endregion 

    #region Ctor 
    public AzureStorageEntityAdapter() 
    { 
     // If you would like to work with objects that do not have a default Ctor you can use (T)Activator.CreateInstance(typeof(T)); 
     this.InnerObject = new T(); 
    } 

    public AzureStorageEntityAdapter(T innerObject) 
    { 
     this.InnerObject = innerObject; 
    } 
    #endregion 

    #region Methods 

    public virtual void ReadEntity(IDictionary<string, EntityProperty> properties, OperationContext operationContext) 
    { 
     TableEntity.ReadUserObject(this.InnerObject, properties, operationContext); 
    } 

    public virtual IDictionary<string, EntityProperty> WriteEntity(OperationContext operationContext) 
    { 
     return TableEntity.WriteUserObject(this.InnerObject, operationContext); 
    } 

    #endregion 
} 

我希望能夠做這樣的事......

public class TableStorageRepository : IRepository 
{ 
    // snip... 

    public IQueryable<T> FindAll<T>() where T : class, new() 
    { 
     CloudTable table = GetCloudTable<T>(); 
     return table.CreateQuery<AzureStorageEntityAdapter<T>>(); 
    } 

    // snip... 
} 

這裏的問題是的createQuery創建

IQueryable<AzureStorageEntityApater<T>>. 

我看不到如何獲得所有'InnerObjects'的IQueryable。

有誰知道是否可以通過某種方式暴露IQueryable而不暴露ITableEntity?

回答

0

這可能是也可能不是你想要的,但可能會給你一些想法。

我創建了一個基礎存儲庫,併爲每個負責傳遞正確的CloudTable,分區/ rowkey /屬性表達式和解析器的實體使用一個單獨的存儲庫。我將它基於DynamicTableEntity(它允許一些高級的東西,如動態在我的實體屬性(如小集合))。

public class BaseRepository 
{ 
    protected async Task<DynamicTableEntity> GetAsync(CloudTable table, Expression<Func<DynamicTableEntity, bool>> filter) 
    { 
     var query = table.CreateQuery<DynamicTableEntity>().Where(filter).AsTableQuery(); 
     var segment = await query.ExecuteSegmentedAsync(null); 
     return segment.Results.FirstOrDefault(); 
    } 

    protected async Task<T> GetAsync<T>(CloudTable table, Expression<Func<DynamicTableEntity, bool>> filter, EntityResolver<T> resolver) 
    { 
     var query = table.CreateQuery<DynamicTableEntity>().Where(filter).Resolve(resolver); 
     var segment = await query.ExecuteSegmentedAsync(null); 
     return segment.Results.FirstOrDefault(); 
    } 

    protected async Task<IEnumerable<DynamicTableEntity>> GetAllAsync(CloudTable table, Expression<Func<DynamicTableEntity, bool>> filter, int take = 1000) 
    { 
     if (take > 10000) take = 10000; 
     if (take < 1) take = 1; 

     var query = table.CreateQuery<DynamicTableEntity>().Where(filter).Take(take).AsTableQuery(); 
     var token = new TableContinuationToken(); 
     var results = new List<DynamicTableEntity>(); 
     while (token != null) 
     { 
      var segment = await query.ExecuteSegmentedAsync(token); 
      results.AddRange(segment.Results); 
      token = segment.ContinuationToken; 
     } 
     return results; 
    } 

    protected async Task<IEnumerable<T>> GetAllAsync<T>(CloudTable table, Expression<Func<DynamicTableEntity, bool>> filter, EntityResolver<T> resolver, int take = 1000) 
    { 
     if (take > 10000) take = 10000; 
     if (take < 1) take = 1; 

     var query = table.CreateQuery<DynamicTableEntity>().Where(filter).Take(take).Resolve(resolver); 
     var token = new TableContinuationToken(); 
     var results = new List<T>(); 
     while (token != null) 
     { 
      var segment = await query.ExecuteSegmentedAsync(token); 
      results.AddRange(segment.Results); 
      token = segment.ContinuationToken; 
     } 
     return results; 
    } 

    protected async Task<int> InsertAsync(CloudTable table, DynamicTableEntity entity) 
    { 
     try 
     { 
      var result = await table.ExecuteAsync(TableOperation.Insert(entity)); 
      return result.HttpStatusCode; 
     } 
     catch (StorageException ex) 
     { 
      return ex.RequestInformation.HttpStatusCode; 
     } 
     catch (Exception ex) 
     { 
      return 500; 
     } 
    } 

    protected async Task<int> ReplaceAsync(CloudTable table, DynamicTableEntity entity) 
    { 
     try 
     { 
      var result = await table.ExecuteAsync(TableOperation.Replace(entity)); 
      return result.HttpStatusCode; 
     } 
     catch (StorageException ex) 
     { 
      return ex.RequestInformation.HttpStatusCode; 
     } 
     catch (Exception ex) 
     { 
      return 500; 
     } 
    } 

    protected async Task<int> DeleteAsync(CloudTable table, DynamicTableEntity entity) 
    { 
     try 
     { 
      var result = await table.ExecuteAsync(TableOperation.Delete(entity)); 
      return result.HttpStatusCode; 
     } 
     catch (StorageException ex) 
     { 
      return ex.RequestInformation.HttpStatusCode; 
     } 
     catch (Exception ex) 
     { 
      return 500; 
     } 
    } 

    protected async Task<int> MergeAsync(CloudTable table, DynamicTableEntity entity) 
    { 
     try 
     { 
      var result = await table.ExecuteAsync(TableOperation.Merge(entity)); 
      return result.HttpStatusCode; 
     } 
     catch (StorageException ex) 
     { 
      return ex.RequestInformation.HttpStatusCode; 
     } 
     catch (Exception ex) 
     { 
      return 500; 
     } 
    } 
} 

一類從它繼承的實例(你必須用你的想象力來填補空白 - 讓我知道,如果你想看到一個正確執行)

// method 
public Task<IEnumerable<T>> GetAllAsync<T>(string pk1, string pk2, EntityResolver<T> resolver, int take = 1000, Expression<Func<DynamicTableEntity, bool>> filterExpr = null) 
    { 
     var keysExpr = x => x.PartitionKey.Equals(string.Format("{0}_{1}", pk1, pk2); 
     var queryExpr = filterExpr != null ? keysExpr.AndAlso(filterExpr) : keysExpr; 
     return base.GetAllAsync<T>(CloudTableSelector.GetTable(), queryExpr, resolver, take); 
    } 

// call 
var products = await ProductRepo.GetAllAsync<ProductOwnerViewDto>(orgType, orgId, ProductOwnerViewDto.GetResolver(), take, x => x.RowKey.CompareTo(fromId) > 0); 

這是一個原始的和痛苦的將所有實體封裝在單獨的回購站中,但是我找不到讓我以這種方式查詢表的方法,同時讓我得到不同的預測(每個表有多個解析器)。

我發現基於ITableEntity限制的解決方案(這是很好的,直到你需要動態屬性,然後你搞砸了)。

+0

感謝您的寶貴意見。雖然不是我想要的,但我很欣賞你的反饋。 我不想用自己的存儲庫注入和包裝系統中的每個實體,我假設公開DynamicTableEntity也帶來了它的存儲庫依賴?首先將ITable解耦使用純POCO的目的是試圖避免這種情況。 我還沒有找到解決方案,我不確定目前存在的解決方案。但我會繼續搜索.. :) –

相關問題