2011-07-11 21 views
0

私は最近、ADO.NET Entity Frameworkの学習と使用を開始し、いくつかの問題にぶつかりました。ネットワークに接続されている別のコンピュータのデータベースに接続できないため、ルータへのWi-Fi接続が切断されることがあります。接続が失敗すると、アプリケーション全体が約20秒間フリーズし、その後例外がスローされます。私は例外をキャッチして代わりにカスタムエラーメッセージを表示したいが、私はすべてのクエリの周りにtry-catchを使いたくない。.NET Entity Frameworkの接続に失敗しました

これは私がやろうとしたものです。私は、必要なたびにコンテキストを作成するための静的メソッドを作成し、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; 
      } 
     } 
    } 
} 

ここで問題は、クエリが実行されているときに例外がスローされ、その後ので、これは動作しないということである

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

...私はEmployeeRepositoryクラスを使用している方法の例だと、コンテキストを作成するときではありません。

だから私の質問....

は、どのように私は、コンテキストが作成されたときに接続エラーをキャッチし、私のカスタムエラーメッセージを表示することができます。

+1

これを2つの質問に分けて、3番目をsuperuser.comまたはserverfault.comに投稿してください。 –

+0

彼の質問はスーパーユーザーまたはserverfaultと何が関係していますか? – Jeff

+0

@ JeffN825ネットワーキングに関連して、それ以前に別の質問がありました。 –

答えて

1

2つのこと:

  1. あなたはアプリがハングアップしたくない場合は、バックグラウンドスレッドでデータ操作を行うべきです。 BackgroundWorkerの使用を検討してください。

  2. 接続はあなたが行うことができ、利用可能であるかどうかを検出するために:

    。独自のEntityConnectionを使用してObjectContextを渡します(既に試した/ try tryブロックで開こうとしました)。 http://msdn.microsoft.com/en-us/library/bb738461.aspx

    b。接続をテストするためにObjectContextを作成した後、myObjectContext.Connection.Openを手動で呼び出します。

    c。 ObjectContextのクエリ可能/クエリープロバイダをラップして、IQueryProvider.Executeメソッドをtry/catchブロックでラップして、切断されたクライアントシナリオを処理します(初心者には推奨されません)。

+0

ありがとう、彼らを試してみましょう。 –

+0

接続を手動で開くと、接続を閉じる必要がありますか?それとも、私の使っている声明がそれを世話しますか? –

+0

はい、手動で開くか、独自の接続オブジェクトを渡すことに決めた場合、その接続の寿命はあなたの責任です。 – Jeff

関連する問題