2011-07-11 158 views
0

我剛剛開始學習和使用ADO.NET實體框架並遇到了一些問題。有時,我的Wifi連接到路由器時發生故障,因此無法連接到網絡中另一臺計算機上的數據庫。失敗的連接導致我的整個應用程序凍結約20秒,然後拋出異常。我想捕捉異常並顯示自定義錯誤消息,但是我不想在每個查詢周圍使用try-catch。.NET實體框架連接失敗

這是我試圖做的。我創建了一個靜態方法來創建一個上下文,每當我需要一個時,並將其包裝在try-catch語句中,以嘗試捕獲連接錯誤,並且在有連接之前不會繼續,或者用戶向MessaeBox回答No並退出應用。

public static MySqlEntities Database 
{ 
    get 
    { 
     try 
     { 
      // create a new context 
      MySqlEntities db = new MySqlEntities(); 

      // return it upon success 
      return db; 
     } 
     catch (Exception ex) 
     { 
      // show error message upon failute 
      MessageBoxResult result = MessageBox.Show("Failed to establish a connection with the database. Please verify that the database server is online, would you like to try again?", "Database Connection Failure", MessageBoxButton.YesNo); 

      // close the application if they don't wanna try again 
      if (result == MessageBoxResult.No) 
      { 
       Fx.Window.Close(); 
       return null; 
      } 

      // otherwise try again 
      return Fx.Database; 
     } 
    } 
} 

這裏是我寫的選擇,更新和添加數據到/從數據庫中的庫類。

public class EmployeeRepository 
{ 
    #region SelectQuery 
    /// <summary> 
    /// Compiled query for selecting a range of Employees. 
    /// </summary> 
    protected static readonly Func<MySqlEntities, int, int, IQueryable<Employee>> SelectQuery = 
     CompiledQuery.Compile<MySqlEntities, int, int, IQueryable<Employee>>(
      (db, start, limit) => 
      (from t in db.Employees orderby t.ID select t).Skip(start).Take(limit) 
     ); 
    #endregion 

    #region SelectyByIDQuery 
    /// <summary> 
    /// Compiled query for selecting a single Employee by ID. 
    /// </summary> 
    protected static readonly Func<MySqlEntities, int, Employee> SelectByIDQuery = 
     CompiledQuery.Compile<MySqlEntities, int, Employee>(
      (db, id) => 
      (from t in db.Employees where t.ID == id select t).FirstOrDefault() 
     ); 
    #endregion 

    #region SelectByUsernameQuery 
    /// <summary> 
    /// Compiled query for selecting a single Employee by Username. 
    /// </summary> 
    protected static readonly Func<MySqlEntities, string, Employee> SelectByUsernameQuery = 
     CompiledQuery.Compile<MySqlEntities, string, Employee>(
      (db, username) => 
      (from t in db.Employees where t.Username == username select t).FirstOrDefault() 
     ); 
    #endregion 

    #region SearchQuery 
    /// <summary> 
    /// Compiled query for searching Employees by Name and Username 
    /// </summary> 
    protected static readonly Func<MySqlEntities, string, int, IQueryable<Employee>> SearchQuery = 
     CompiledQuery.Compile<MySqlEntities, string, int, IQueryable<Employee>>(
      (db, search, limit) => 
      (from t in db.Employees where t.Name.StartsWith(search) || t.Username.StartsWith(search) select t).Take(limit) 
     ); 
    #endregion 

    /// <summary> 
    /// Select a range of Employees start at a specific offset. 
    /// </summary> 
    /// <param name="start">The starting position.</param> 
    /// <param name="limit">The maximum number of employees to select.</param> 
    /// <returns></returns> 
    public static List<Employee> Select(int start = 0, int limit = 10) 
    { 
     using (var db = Fx.Database) 
      return new List<Employee>(SelectQuery.Invoke(db, start, limit)); 
    } 

    /// <summary> 
    /// Select a single Employee with a matching ID. 
    /// </summary> 
    /// <param name="id">The ID to search for.</param> 
    /// <returns></returns> 
    public static Employee SelectByID(int id) 
    { 
     using (var db = Fx.Database) 
      return SelectByIDQuery.Invoke(db, id); 
    } 

    /// <summary> 
    /// Select a single Employee with a matching Username. 
    /// </summary> 
    /// <param name="username">The Username to search for.</param> 
    /// <returns></returns> 
    public static Employee SelectByUsername(string username) 
    { 
     using (var db = Fx.Database) 
      return SelectByUsernameQuery.Invoke(db, username); 
    } 

    /// <summary> 
    /// Search for Employees by Name and Username. 
    /// </summary> 
    /// <param name="search">The search string.</param> 
    /// <param name="limit">The maximum number of Employees to select.</param> 
    /// <returns></returns> 
    public static List<Employee> Search(string search, int limit = 10) 
    { 
     using (var db = Fx.Database) 
      return new List<Employee>(SearchQuery.Invoke(db, search, limit)); 
    } 


    /// <summary> 
    /// Save changes to an Employee to the database. 
    /// </summary> 
    /// <param name="employee">The Employee object to save.</param> 
    public static bool Save(Employee employee) 
    { 
     using(var db = Fx.Database) 
     { 
      db.Employees.Attach(employee); 
      db.Employees.Context.ObjectStateManager.ChangeObjectState(employee, System.Data.EntityState.Modified); 
      try 
      { 
       db.SaveChanges(); 
       return true; 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("Failed to save employee:\n\n" + ex.InnerException.Message); 
       return false; 
      } 
     } 
    } 

    /// <summary> 
    /// Add an Employee to the database. 
    /// </summary> 
    /// <param name="employee">The Employee object to add.</param> 
    public static bool Add(Employee employee) 
    { 
     using (var db = Fx.Database) 
     { 
      db.Employees.AddObject(employee); 
      try 
      { 
       db.SaveChanges(); 
       return true; 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("Failed to add employee:\n\n" + ex.InnerException.Message); 
       return false; 
      } 
     } 
    } 
} 

這裏是我如何使用EmployeeRepository類的例子...

Employee Employee = EmployeeRepository.SelectByUsername(UsernameInput.Text); 
if(Employee == null || Employee.Password != PasswordInput.Password) 
    MessageBox.Show("Invalid login credentials."); 
else 
    MessageBox.Show("Logged in successfully."); 

的問題是,這不起作用,因爲正在執行查詢時異常被拋出之後和不是當我創建上下文時。

所以我的問題....

我怎樣才能趕上連接錯誤,創建並顯示我的自定義錯誤消息的上下文時。

+1

請將此分成兩個問題,然後在superuser.com或serverfault.com上發佈您的第三個問題。 –

+0

他的問題與超級用戶或serverfault有什麼關係? – Jeff

+0

@ JeffN825在那之前我還有一個問題涉及更多的網絡問題。 –

回答

1

兩件事情:

  1. 如果您不希望應用程序掛斷,你應該在後臺線程做數據操作。考慮使用BackgroundWorker。

  2. 要檢測的連接是可用的,你可以這樣做:

    一個。傳入您自己的EntityConnection以使用ObjectContext(您已經在try catch塊中測試/嘗試打開)。 http://msdn.microsoft.com/en-us/library/bb738461.aspx

    b。在創建ObjectContext來測試連接後,手動調用myObjectContext.Connection.Open。

    c。用你自己的包裹ObjectContext的可查詢/查詢提供程序,用try/catch塊封裝IQueryProvider.Execute方法來處理斷開連接的客戶端場景(不建議初學者)。

+0

好的,非常感謝,會嘗試一下。 –

+0

如果我手動打開連接,我是否也必須關閉它?或者我的使用說明會處理這個問題嗎? –

+0

是的,如果您手動打開它或決定傳入您自己的連接對象,則需要對其壽命負責。 – Jeff