Сбой подключения .NET Entity Framework - PullRequest
0 голосов
/ 11 июля 2011

Я только недавно начал изучать и использовать 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.");

Проблема в том, что это не работает, потому что исключение выдается впоследствии при выполнении запроса, а не при создании контекста.

Так что мой вопрос....

Как я могу отловить ошибку соединения при создании контекста и отобразить свое собственное сообщение об ошибке.

1 Ответ

1 голос
/ 11 июля 2011

Две вещи:

  1. Если вы не хотите, чтобы приложение зависало, вы должны выполнять операции с данными в фоновом потоке. Рассмотрите возможность использования BackgroundWorker.

  2. Чтобы определить, доступно ли соединение, вы можете сделать:

    а. Передайте свой собственный EntityConnection для использования ObjectContext (который вы уже тестировали / пытались открыть в блоке try catch). http://msdn.microsoft.com/en-us/library/bb738461.aspx

    б. Вручную вызовите myObjectContext.Connection.Open после создания ObjectContext для проверки соединения.

    с. Оберните источник запросов / запросов ObjectContext своим собственным, который обертывает метод IQueryProvider.Execute блоком try / catch для обработки сценария отключенного клиента (не рекомендуется для начинающих).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...