0

我在 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的用户ID 为 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);修复它,然后它工作正常。似乎是一些缓存问题。但是,我当然不想那样修复它。更改代码以便在查询后不释放数据上下文并不能解决问题。

4

5 回答 5

1

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

由于您显然每次都会获得新的数据上下文,因此我认为这不是罪魁祸首。但是,我也对代码的工作感到有些惊讶......你确定这是有代表性的吗?

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

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

于 2009-06-04T16:55:12.677 回答
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(); ;
        }
    }
}
于 2009-06-04T17:21:17.090 回答
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。

另一件可能引起麻烦的事情是,当数据上下文已经被释放时,您开始枚举。解决这个问题的唯一方法是根本不释放它(当它超出范围时依赖 GC 清理它),或者想出一个自定义的 IDisposable 对象,这样你就可以在它周围放置一个 using。就像是:

using(var inboxMessages = this.messageRepository.GetInbox(userId1))
{
    Assert.That(inboxMessages.All(m => m.MessageTo == userId1);
}
于 2009-06-04T18:00:37.250 回答
1

好吧,这似乎是 DbLinq 的问题。我使用了 3 周前的源代码,QueryCache 中有一个明显的错误(尽管它一直存在)。这里有一个完整的线程。

我更新了 dblinq 源。Querycache 现在被禁用(确实意味着性能下降)并且至少现在它可以正常工作。我得看看性能是否可以接受。必须承认我有点困惑,因为我正在尝试做的是一个常见的 linq2sql 模式。谢谢大家。

于 2009-06-05T11:23:08.623 回答
0

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

...您已被警告!

于 2009-11-05T14:00:39.057 回答