.NET实体框架连接失败

时间:2011-07-11 18:21:44

标签: c# wpf entity-framework

我刚刚开始学习和使用ADO.NET实体框架并遇到了一些问题。有时我与路由器的Wifi连接中断,所以我无法连接到网络中另一台计算机上的数据库。连接失败导致我的整个应用程序冻结大约20秒然后抛出异常。我想捕获异常并显示自定义错误消息,但是我不想在每个查询周围使用try-catch。

这是我试图做的。我创建了一个静态方法来在每次需要时创建一个上下文并将其包装在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 个答案:

答案 0 :(得分:1)

两件事:

  1. 如果您不希望应用程序挂断,则应该在后台线程上执行数据操作。考虑使用BackgroundWorker。

  2. 要检测连接是否可用,您可以执行以下操作:

    一个。传入您自己的EntityConnection以供ObjectContext使用(您已经测试/尝试在try catch块中打开)。 http://msdn.microsoft.com/en-us/library/bb738461.aspx

    湾在创建ObjectContext以测试连接后,手动调用myObjectContext.Connection.Open。​​

    ℃。使用您自己的ObjectContext的可查询/查询提供程序包装,使用try / catch块包装IQueryProvider.Execute方法来处理断开连接的客户端方案(不建议初学者使用)。