2015-02-23 16 views
0

我有一種方法可以根據給定的參數從不同的存儲庫中檢索數據。簡化方法從通用存儲庫檢索數據

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是所有關於重複和args.Id如果EntityArgs所有有效的cases回報Content。內容始終是複雜的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; } 
} 

庫是這樣實現的,在那裏是SQLiteDataProvider包裝紙圍繞SQLite-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; 

...當然以上都不行,因爲我需要知道與底層數據庫表對應的具體類。

我只是無法繞過它。想法?

+0

原始代碼似乎很清楚 - 你爲什麼要這樣做? – Hogan 2015-02-23 16:56:17

+0

羅特的原因。其中一個是單元測試,我只想通過模擬Repository 。 – 2015-02-23 16:59:22

回答

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; 
    } 
} 
+0

謝謝,我需要試試這個。更好的是,我希望有一種'公共虛擬RepoResolver'方法返回正確的存儲庫,我可以在單元測試時重寫。 – 2015-02-23 17:04:25

+0

你也可以這樣做,但這並不能完全幫助你從實體中檢索內容。您可能需要一個存儲庫的接口,然後返回一個實體;但只返回*實體(而不是特定子類型)的存儲庫並不真正有用(除了訪問內容) – poke 2015-02-23 17:14:15