LINQ DataContext是许多插入的最佳实践

时间:2012-06-15 06:31:42

标签: linq linq-to-sql optimization

我有一个记录器类,在我的应用程序中使用,包括请求和线程。记录器由每个Log.Insert(字符串文本)的数据库插入组成。记录器是一个静态类,并为每次调用Insert创建一个新的数据库上下文。可能会有很多对Insert的调用,并且许多数据库上下文同时不适合优化。 (我有时会因为整个应用程序中的sql操作太多而导致数据库超时 - 因此确实需要进行优化。)

可以通过在Logger类的静态成员中创建和存储单个数据库上下文来优化它,该成员仅用于Log.Inserts吗?或者这会失败吗?

记录器类的简化版本;

[Table]
public class Log
{
   [Column]
   public string Text { get; set; }

   private static DataContext DatabaseContextInsert { get; set; }

   public static void Insert(string text)
   {
      if (DatabaseContextInsert == null)
      {
          DatabaseContextInsert = DataContextHelper.GetDataContext();            
      }

      var log = new Log { Text = text };          

      lock (DatabaseContextInsert)
      {
        DatabaseContextInsert.GetTable<Log>().InsertOnSubmit(log);
        DatabaseContextInsert.SubmitChanges();
      }
   }
}

1 个答案:

答案 0 :(得分:2)

使用静态记录器将是一个非常糟糕的主意。除了同步问题之外,您将永远遇到数据上下文中所有项目的问题(数据上下文喜欢保留它所见过的对象)。

你提到你认为很多数据上下文不利于优化,但是连接可能已经汇集(默认情况下就是这样),因此数据上下文实际上并不是非常“重”。

如果不需要同步插入日志条目,我会尝试做一些事情,例如将新的日志项投入队列(同步访问),以及让工作线程每隔10秒清空队列,基本上做类似的东西:

// adding an item
lock(queue) { queue.Enqueue(text); }


// worker code, every 10 seconds
List<string> items = new List<string>();
lock(queue) {
    while(queue.Count != 0) items.Add(items.Dequeue);
}
using(var ctx = CreateContext()) {
    foreach(var text in items) {
        ctx.Logs.InsertOnSubmit(new Log { Text = text });
    }
    ctx.SubmitChanges();
}

然后只有一个线程正在写入数据库,并且您的事务少得多。

如果这个不是一个选项,并且你需要同步进行,那么坦率地说,我会将一些级别下降到类似“dapper”的东西,即

using(var conn = CreateOpenConnection()) {
    conn.Execute("insert [Log]([Text]) values(@text)", new {text});
}

在所有中删除了对数据上下文的需求,简单得多,并且不考虑事务。