是否可以为 Azure 表制作 IQueryable<Poco> 存储库



我想知道是否可以按照这条线制作一些东西。

public interface ITableRepository<TModel>{
    IQueryable<TModel> GetAll();
}
public class TableRepository<TModel> : ITableRepository<TModel>
{
    private readonly CloudTable _table;
    private readonly Func<DynamicTableEntity, TModel> _serializer;
    public TableRepository(CloudTable table,  Func<DynamicTableEntity,TModel> serializer)
    {
        this._table = table;
    }
    public IQueryable<TModel> GetAll()
    {
        var query = from ent in this._table.CreateQuery<DynamicTableEntity>()
                    select _serializer(ent);
        return query;
    }
}

目标是让我的模型不从TableEntity派生,我接受我必须写的方法接受DynamicTableEntity和给我的模型。

我假设在这里给出的代码中,如果有人使用GetAll()并在之后应用一些过滤器,它将首先从表中获取所有实体,然后应用我的序列化器函数和过滤器,这是我不想要的。

它的内部使用,因此存储库的用户知道它是一个表存储库,并且可以假设他知道一些查询不能像他在LINQ中使用的那样执行。

可以改成TableQuery而不是IQueryable。

但是,如果存储库的用户可以轻松地添加自己的过滤器,而这些过滤器将应用于表服务而不是内存,那么是否可以这样做呢?

这绝对是可能的:The goal is to have my Model not derive from TableEntity,这也是非常少的代码。

这可以通过使用适配器模式完成。

创建一个基类,您的模型类从中派生:

public class StorageTableEntityBase
{
public string ETag { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
#region ctor
public StorageTableEntityBase()
{
}
public StorageTableEntityBase(string partitionKey, string rowKey)
{
    PartitionKey = partitionKey;
    RowKey = rowKey;
}
#endregion
}

创建一个适配器类来完成读写部分:

internal class AzStorageEntityAdapter<T> : ITableEntity where T : StorageTableEntityBase, 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 AzStorageEntityAdapter()
{
    // 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 AzStorageEntityAdapter(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
}

我将这个类标记为内部的,因此可以避免公开暴露Azure存储库。这是所有需要的代码。

用法:

定义Model类:

public class UserEntity : StorageTableEntityBase
{
    public string UserName { get; set; }
    public string Email { get; set; }
}

从存储表中检索:

public T RetrieveEntity<T>(string tableName, string partitionKey, string rowKey)
        where T : StorageTableEntityBase, new()
{
    CloudTable table = TableClient.GetTableReference(tableName);
    TableResult tableResult = table.Execute(TableOperation.Retrieve<AzStorageEntityAdapter<T>>(partitionKey, rowKey));
    if (tableResult.Result != null)
    {
        return ((AzStorageEntityAdapter<T>)tableResult.Result).InnerObject;
    }
    return default(T);
}

相关内容

  • 没有找到相关文章

最新更新