在数据库查询中使用关键字async / await

时间:2014-01-26 00:27:56

标签: c# windows-phone-7 windows-phone-8 thread-safety async-await

我在Windows Phone 8 app中有一个本地数据库。该应用程序包含对数据库的大量查询,我不希望对UI的响应性产生不良影响。

例如,我有一个用户表和方法,用于通过id从数据库中获取用户。

当前变体

public class CacheDataContext : DataContext
{
    public static string DBConnectionString = "Data Source=isostore:/Cache.sdf";

    public CacheDataContext(string connectionString)
            : base(connectionString) { }

    public static AutoResetEvent OperationOnDatabaseUser = new AutoResetEvent(true);

    public Table<User> UserItems;
}

public class CacheDataContextUser : CacheDataContext
{
    public CacheDataContextUser(string connectionString)
        : base(connectionString) { }

    public User GetUser(string id)
    {
        try
        {
            OperationOnDatabaseUser.WaitOne();
            using (CacheDataContext context = new CacheDataContext(DBConnectionString))
            {
                //find user in the data base and return 
            }
        }
        finally
        {
            OperationOnDatabaseUser.Set();
        }
    }
}

如果数据库同时允许不同的请求添加,更新,删除数据,我需要确保数据的安全性。为此我使用AutoResetEvent。不确定我做得对,但到目前为止没有问题。

我可以从数据库中获取用户:

using (DataBaseUser = new CacheDataContextFriends(ConnectionString))
{
   var user = DataBaseUser.GetUser(id);
}

异步/ AWAIT

但我希望使用关键字async / await来处理数据库。

public class CacheDataContextUser : CacheDataContext
{
    public CacheDataContextUser(string connectionString)
        : base(connectionString) { }

    private object threadLock = new object();

    public Task<User> GetUser(string id)
    {       
        using (CacheDataContext context = new CacheDataContext(DBConnectionString))
        {
            var result = await Task<User>.Factory.StartNew(() =>
                {
                    lock (threadLock)
                    {
                       //find user in the data base and return  
                    }                  
                });
            return result;          
        }       
    }
}

我害怕改写上面描述的方法,因为我不确定它是对的。请告诉我可能是什么问题。我的主要目标是提高应用程序的响应能力。

1 个答案:

答案 0 :(得分:6)

首先,AutoResetEvent用于独占访问是错误的。在Windows中,像这样的“事件”是从一个线程到另一个线程的消息;在这种情况下,你只需要一个简单的锁:

public class CacheDataContext : DataContext
{
  public static string DBConnectionString = "Data Source=isostore:/Cache.sdf";

  public CacheDataContext(string connectionString)
        : base(connectionString) { }

  protected static readonly object OperationOnDatabaseUser = new object();

  public Table<User> UserItems;
}

public class CacheDataContextUser : CacheDataContext
{
  public CacheDataContextUser(string connectionString)
    : base(connectionString) { }

  public User GetUser(string id)
  {
    lock (OperationOnDatabaseUser)
    {
        using (CacheDataContext context = new CacheDataContext(DBConnectionString))
        {
            //find user in the data base and return 
        }
    }
  }
}

如果您想提高响应能力,请使用Task.Run调用您的数据上下文方法,即:

var user = await Task.Run(() => GetUser(id));

除非实际的数据库访问是异步的(即使用EF6,不是 Task.Run),否则不要在数据上下文中公开异步方法。