2013-08-27 19 views
2

我想知道是否有更好的方法來解決我忽略的這個問題。 (我正在尋找第二個意見)有沒有更好的方法將對象從數據庫查詢映射到對象?

我想創建一個通用和簡單的方法來綁定對象到數據庫閱讀器查詢使用「Oracle.DataAccess.Client」。

爲了做到這一點,我最初想創建一個從OracleCommand繼承的對象;但是,OracleCommand是一個密封的對象。

爲了解決這個問題,我決定創建一個擴展方法,試圖將對象映射到數據庫中的每一行的通用列。

編輯:在我的情況下,我知道數據庫將看起來像什麼;但是,在運行時,我不知道數據庫在哪裏。即數據庫可能已經提前傳輸,並且最終用戶將在運行時指定數據庫的憑證。

下面是執行:

public static T[] Bind<T>(this OracleCommand oe, Binding binding, CommandBehavior Behavior = CommandBehavior.Default) 
    { 
     List<T> ret = new List<T>(); 

     using (var reader = oe.ExecuteReader(Behavior)) 
     { 
      while (reader.Read()) 
      { 
       T unknownObj = (T)Activator.CreateInstance(typeof(T)); 
       for (int i = 0; i < binding.GetBindCount(); i++) 
       { 
        var propinfo = unknownObj.GetType().GetProperties().ToList(); 
        var prop = propinfo.Find((p) => p.Name == binding.GetBindValue(i, true)); 
        prop.SetValue(unknownObj, reader[binding.GetBindValue(i, false)]); 
       } 
       ret.Add(unknownObj); 
      } 
     } 
     return ret.ToArray(); 
    } 
} 

public class Binding 
{ 

    List<BindingMap> _map = new List<BindingMap>(); 


    public void AddBind(String VariableName, String ColumnName) 
    { 
     _map.Add(new BindingMap(VariableName, ColumnName)); 
    } 
    public String GetBindValue(int index, bool IsVariable = true) 
    { 
     var a = _map.ToArray(); 
     return (IsVariable) ? a[index].Variable : a[index].Column; 
    } 

    public int GetBindCount() 
    { 
     return _map.Count; 
    } 
} 

public class BindingMap 
{ 
    public String Column; 
    public String Variable; 

    public BindingMap(String v, String c) 
    { 
     Variable = v; 
     Column = c; 
    } 
} 

有沒有更好的方式來做到這一點,我已經忽略了,或者這是一個聲音?

,將在真正的代碼中使用的方法是這樣的:

static void Main() 
    {   
     Binding b = new Binding(); 
     b.AddBind("CreatedBy", "Create_by"); 


     using (var Conn = new OracleConnection()) 
     { 
      Conn.ConnectionString = od.Options.GetConnectionString(); 
      using (var Command = new OracleCommand()) 
      { 
       Command.Connection = Conn; 
       Command.CommandText = "Select * From Accounts"; 

       Conn.Open(); 

       var a = Command.Bind<Account>(b); 
       foreach (Account e in a) 
       { 
        Console.WriteLine(e.CreatedBy); 
       } 
      } 
     } 
     Console.Read(); 
    } 

    public class Account 
    { 
     public String CreatedBy 
     { 
      get; 
      set; 
     } 

    } 
+8

井的問題,使用ORM?你不需要重新發明輪子。 –

+4

'是否有更好的方法將對象從數據庫查詢映射到對象? - 是的,它被稱爲[實體框架](http://msdn.microsoft.com/zh-cn/data/aa937723)。我在日常基礎上看到的類似問題的數量讓我覺得微軟不會公開它的[數據訪問技術](http://msdn.microsoft.com/zh-cn/data/aa937685.aspx)好。 –

+0

同意,ORM是要走的路。你可以使用EF http://stackoverflow.com/questions/82644/can-you-use-microsoft-entity-framework-with-oracle –

回答

0

作爲一個稍微好一點的方式,你可以像Telerik的不指定綁定屬性:用LINQ表達式。這是用法。相反的:

AddBind("CreatedBy", "Created_by"); 

你會寫

AddBind(x => x.CreatedBy, "Created_by"); 

你得到一個稍微強打字的機會。的AddBind簽名是:

public void AddBind<T>(Expression<Func<Account, T>> variable, string columnName) { 
    // ... 
} 

但我不會進入的通用功能的方式。我寧願超載非通用函數:

public void AddBind(Expression<Func<Account, double>> variable, string columnName) { 
    // Add binding for double 
} 

public void AddBind(Expression<Func<Account, DateTime>> variable, string columnName) { 
    // Add binding for DateTime 
} 

// ... 

然後將根據您的映射對象的類型選擇綁定的類型。這樣可以防止您錯誤地記錄您的屬性​​,因此您可以在Account類中保留執行名稱更改的可能性,而不會中斷綁定。

列名仍然是string,對不起。

當然,那麼泛化的方式是使你的BindingMap通用。 (以你的業務類作爲一個類型參數)

class BindingMap<BusinessClass> { 
    // .... 

    public void AddBind(Expression<Func<BusinessClass, double>> variable, string columnName) { 
     // Add binding for double 
    } 

    public void AddBind(Expression<Func<BusinessClass, DateTime>> variable, string columnName) { 
     // Add binding for DateTime 
    } 

    // ... 
}; 

我離開作爲exercice給你挖屬性描述出來的表情:)