我有一个包含30多个项目的大型应用程序,目前使用的是IRepository和POCO实体。我想知道是否有办法使用表存储而无需实现ITableEntity。我不想将azure存储块包导入到每个项目中,并将我的所有实体更改为使用ITableEntity。
实体适配器
我知道可以创建一个实体适配器(例如下面的那个),它在读取或编写单个实体时非常有效。但是,当尝试通过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 :(得分: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限制的解决方案(直到你需要动态属性然后你才搞砸了)。