Я только недавно начал изучать и использовать ADO.NET Entity Framework и столкнулся с несколькими проблемами.Иногда мое Wi-Fi соединение с маршрутизатором разрывается, поэтому я не могу подключиться к базе данных, которая находится на другом компьютере в сети.Неудачное соединение заставляет мое приложение зависать примерно на 20 секунд, а затем выдает исключение.Я хочу перехватить исключение и вместо этого показать собственное сообщение об ошибке, однако я не хочу использовать try-catch для каждого запроса.
Вот что я пытался сделать.Я создал статический метод для создания контекста каждый раз, когда он мне нужен, и обернул его внутри оператора try-catch, чтобы попытаться перехватить ошибку соединения и не двигаться дальше, пока не будет установлено соединение или пользователь не ответит «Нет» на MessaeBox и не выйдет изapplication.
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;
}
}
}
}
Вот пример того, как я использую EmployeeRepositoryclass ...
Employee Employee = EmployeeRepository.SelectByUsername(UsernameInput.Text);
if(Employee == null || Employee.Password != PasswordInput.Password)
MessageBox.Show("Invalid login credentials.");
else
MessageBox.Show("Logged in successfully.");
Проблема в том, что это не работает, потому что исключение выдается впоследствии при выполнении запроса, а не при создании контекста.
Так что мой вопрос....
Как я могу отловить ошибку соединения при создании контекста и отобразить свое собственное сообщение об ошибке.