DbLinq - 缓存问题

时间:2009-06-04 16:24:30

标签: c# caching datacontext dblinq

我在ASP.NET MVC网站上使用linq to sql for MySql(使用DbLinq)。我有一个奇怪的缓存问题。请考虑我的Repository类中的以下方法:

public IEnumerable<Message> GetInbox(int userId)
{
  using(MyDataContext repo = new MyDataContext(new MySqlConnection("[Connectionstring]")))
  {
    return repo.Messages.Where(m => m.MessageTo == userId);
  }
}

public IEnumerable<Message> GetOutbox(int userId)
{
  using (MyDataContext repo = new MyDataContext(new MySqlConnection("[Connectionstring]")))
  {
    return repo.Messages.Where(m => m.MessageFrom == userId);
  }
}

'MyDataContext'是由DbLinq生成的映射到我的数据库,它继承自DataContext。我不是在这里重用datacontext(上面的代码看起来有点傻但我想绝对确定它不是一些datacontext / mysqlconnection重用问题)。

无论userId如何,无论使用哪种方法,结果都保持不变。期。即使我可以看到repo.Messages的结果超过10个,但MessageFromMessageTo值不同,我只会得到第一个查询结果。因此,如果我拨打GetInbox(4374),它会向我显示消息A和消息B.之后呼叫GetInbox(526)仍然会向我发送消息A和B,即使消息C和D谁< em> do 的userId为526.我必须重新启动应用程序才能看到任何更改。

这里发生了什么?我确定我做的事情太愚蠢了,当有人向我指出时,我会感到羞耻。如果我没有做一些非常愚蠢的事情,那么我觉得这个问题很奇怪。我读过没有重用DataContext,但我不是。为什么这个缓存问题?下面是我的控制器代码,但我怀疑这很重要:

[Authorize]
public ActionResult Inbox(int userId)
{
  Mailbox inbox = new Mailbox(userId, this.messageRepository.GetInbox(userId));
  return PartialView("Inbox", inbox);
}

虽然在SO上有类似的问题,但我还没有找到这个确切问题的答案。非常感谢!

更新: 将代码更改为:return repo.Messages.ToList().Where(m => m.MessageFrom == userId);修复它,它可以正常工作。好像有些缓存问题。但是,我当然不希望以这种方式修复它。 更改代码以便在查询后不处理datacontext 解决问题。

5 个答案:

答案 0 :(得分:1)

LINQ-to-SQL中的缓存与DataContext相关联,主要限于身份缓存 - 在大多数情况下,即使您之前已经完成,它也会重新运行查询。有一些例子,比如.Single(x=>x.Id == id)(有特殊处理)。

由于您每次都清楚地获得新的数据上下文,我认为这不是罪魁祸首。但是,我对代码的工作方式感到有些惊讶......你确定它具有代表性吗?

LINQ的Where方法被延迟 - 意味着在迭代数据之前不会执行它(例如使用foreach)。但到那时你已经处理了数据上下文!你从这个例子中剪了一些东西吗?

另外 - 通过给它一个SqlConnection(那时你没有Dispose()),你可能会影响清理 - 可能最好只给它(数据上下文)连接字符串。

答案 1 :(得分:1)

我写了一些非常相似的代码似乎工作得很好。唯一的区别是,正如Marc建议的那样,我传入连接字符串并在Where方法上调用ToList。我的数据库不是自动生成的,而是从DataContext派生的。代码如下。

class Program
{
    static void Main(string[] args)
    {
        List<Item> first = GetItems("F891778E-9C87-4620-8AC6-737F6482CECB").ToList();
        List<Item> second = GetItems("7CA18DD1-E23B-41AA-871B-8DEF6228F96C").ToList();
        Console.WriteLine(first.Count);
        Console.WriteLine(second.Count);
        Console.Read();
    }

    static IEnumerable<Item> GetItems(string vendorId)
    {
        using (Database repo = new Database(@"connection_string_here"))
        {
            return repo.GetTable<Item>().Where(i => i.VendorId.ToString() == vendorId).ToList(); ;
        }
    }
}

答案 2 :(得分:1)

开始写测试。这将告诉你Linq2Sql是否正常运行。类似的东西:

var inboxMessages = this.messageRepository.GetInbox(userId1);
Assert.That(inboxMessages.All(m => m.MessageTo == userId1);

inboxMessages = this.messageRepository.GetInbox(userid2);
Assert.That(inboxMessages.All(m => m.MessageTo = userid2);

如果成功,你应该检查是否是导致问题的延迟执行。您应该立即枚举inboxMessages。

可能导致问题的另一个原因是,您已经开始枚举datacontext已经处理好的事实。解决这个问题的唯一方法就是不要处理它(并且当它超出范围时依赖GC清理它),或者想出一个自定义IDisposable对象,这样你就可以使用它了。类似的东西:

using(var inboxMessages = this.messageRepository.GetInbox(userId1))
{
    Assert.That(inboxMessages.All(m => m.MessageTo == userId1);
}

答案 3 :(得分:1)

好吧,这似乎与DbLinq有关。我使用了3周大的源代码,在QueryCache中有一个显着的错误(虽然总是在那里)。有一个完整的主题涵盖了这个here

我更新了dblinq源代码。 Querycache现在已被禁用(确实意味着性能受到影响),至少现在它可以正常运行。我必须看看性能是否可以接受。必须承认我有点困惑,因为我正在尝试做的是一个常见的linq2sql模式。谢谢大家。

答案 4 :(得分:0)

我避免将DBLinq用于生产代码......许多Linq-To-SQL的功能都没有实现,并且遍历源代码显示成熟度很低......许多方法都没有实现或标记为“未终止”。

......你被警告了!