简化从通用存储库检索数据的方法

时间:2015-02-23 16:40:01

标签: c# .net generics

我有一个方法可以根据给定的参数从不同的存储库中检索数据。

private async Task<string> GetByIdFrom(EntityArgs args)
{
    string content = null;
    switch (args.CollectionName.ToLowerInvariant())
    {
        case Common.WorkingSite:
            var workingsite = await (new Repository<WorkingSite>())
                .GetByKeyAsync(args.Id);
            if (workingsite != null)
                content = workingsite.Content;
            break;
        case Common.ProductInstruction:
            var productInfo = await (new Repository<ProductInstruction>())
                .GetByKeyAsync(args.Id);
            if (productInfo != null)
                content = productInfo.Content;
            break;
        case Common.Resource:
            var resource = await (new Repository<Resource>())
                .GetByKeyAsync(args.Id);
            if (resource != null)
                content = resource.Content;
            break;
        default:
            Logger.Warn("GetById(): Table {0} not found", args.CollectionName);
            break;
    }
    return content;
} 

如果switch有效,您可以看到cases完全是重复,Content全部args.Id返回EntityArgs。内容总是复杂的JSON。

CollectionName属性为string,因为请求来自JavaScript客户端; CollectionName只是在.NET部分上标识SQLite表。

Repository<T>的所有上述类都实现了相同的抽象基础Entity

[JsonObject]
public abstract class Entity
{
    protected Entity()
    {}

    [PrimaryKey]
    [JsonProperty(PropertyName = "id")]
    public int Id { get; set; }

    [JsonIgnore]
    public string Content { get; set; }
}

存储库实现如下,其中SQLiteDataProviderSQLite-net ORM的包装,连接到本地SQLite数据库。

public class Repository<T> where T : new()
{
    private readonly Logger _logger = LogManager.GetCurrentClassLogger();

    /// <summary>
    /// Get by primary key
    /// </summary>
    public virtual async Task<T> GetByKeyAsync(object key)
    {
        var item = default(T);

        try
        {
            item = await SQLiteDataProvider.Connection.GetAsync<T>(key);
        }
        catch (Exception e)
        {
            if ((e is InvalidOperationException) && e.Message.Contains("no elements"))
            {
                _logger.Info("GetByKeyAsync<{0}> - {1}", (typeof(T)).Name, e.Message);
            }
            else
            {
                _logger.Error(e);
                throw;    
            }
        }
        return item;
    }

    // ...other methods
}

我非常确定我应该能够摆脱整个switch语句,只需要调用类似

的内容
var item = await (new Repository<Entity>()).GetByKeyAsync(args.Id);
return item != null ? item.Content : null;

...当然上面没有工作,因为我需要知道对应底层数据库表的具体类。

我无法理解它。想法?

1 个答案:

答案 0 :(得分:1)

Sicne所有类型都实现Entity,您可以创建一个通用方法,要求type参数继承它,以便您可以访问Content属性。

private async Task<string> GetByIdFrom<T>(EntityArgs args)
    where T : Entity
{
    T entity = await (new Repository<T>()).GetByKeyAsync(args.Id);
    if (entity != null)
        return entity.Content;

    return null;
}

请注意,您仍然需要一个包含交换机的非泛型方法,以便根据args.CollectionName选择要遵循的路径。但至少它变得更加简洁:

private async Task<string> GetByIdFrom(EntityArgs args)
{
    switch (args.CollectionName.ToLowerInvariant())
    {
        case WorkingSite:
            return GetByIdFrom<WorkingSite>(args);
        case ProductInstruction:
            return GetByIdFrom<ProductInstruction>(args);
        case Resource:
            return GetByIdFrom<Resource>(args);
        default:
            Logger.Warn("GetById(): Table {0} not found", args.CollectionName);
            break;
    }
}