2015-10-16 30 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的目的是试图避免这种情况。 我还没有找到解决方案,我不确定目前存在的解决方案。但我会继续搜索.. :) –

相关问题