سؤال

I am wondering if something along the lines of this can be made.

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;

    }
}

The goal is to have my Model not derive from TableEntity and I accept that I have to write methods that takes DynamicTableEntity and give me my model.

I assume that with the given code here if someone uses GetAll() and applying some filters after that it will first get all entities from the table and apply my serializer func and filter after, which i do not want.

Its internal use so the user of the repository know that it is a table repository and it may be assumed he knows that some queries can not be performed like he is used to in LINQ.

Possible it could be changed to TableQuery instead of IQueryable.

But can something like this be done where the user of the repository can easily add his onw filters that would be applied on the table service and not in memory?

هل كانت مفيدة؟

المحلول

This is definitely possible: The goal is to have my Model not derive from TableEntity, that too with very minimal code.

This can be done by using adapter pattern.

Create a Base class from which your Model classes derive from:

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
}

Create an adapter class which does the reading and writing part:

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
}

I mark this class as internal, so exposing Azure Storage Library publicly can be avoided. And this is all the code required.

Usage:

Define a Model class:

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

Retrieving from the storage table:

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);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top