是否可以创建用于azure表的IQueryable <poco>存储库</poco>

时间:2014-03-30 21:26:51

标签: linq azure azure-table-storage

我想知道是否可以做出类似的事情。

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。

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

1 个答案:

答案 0 :(得分:1)

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

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

创建一个Model类派生自的Base类:

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);
}