DbLinq - 缓存问题

发布于 2024-07-24 03:44:21 字数 1667 浏览 15 评论 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。 我在这里没有重用数据上下文(上面的代码看起来有点傻,但我想绝对确保这不是某些数据上下文/mysqlconnection 重用问题)。

发生的情况是,无论我使用什么 userId 调用这两个方法中的任何一个,结果都保持不变。 时期。 尽管我可以看到 repo.Messages 有超过 10 个结果,并且 MessageFromMessageTo 值不同,但我只得到第一个查询的结果结果返回。 因此,如果我调用 GetInbox(4374),它会给我消息 A 和消息 B。之后调用 GetInbox(526) 仍然会给我消息 A 和 B,即使有 消息 C 和 D 的 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); 修复它,然后就可以正常工作了。 看起来像一些缓存问题。 但是,我当然不想那样解决它。 更改代码以便在查询后不释放数据上下文并不能解决问题。

I'm using linq to sql for MySql (using DbLinq) in an ASP.NET MVC website. I have a weird caching problem. Consider the following methods in my Repository class:

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' is the by DbLinq generated mapping to my database, which inherits from DataContext. I'm not reusing the datacontext here (the above code looks a bit silly but I wanted to make absolutely sure that it was not some datacontext / mysqlconnection re-using issue).

What happens is, whichever of the two methods I call, with whatever userId, the results stay the same. Period. Even though I can see that repo.Messages has more than 10 results, with varying MessageFrom and MessageTo values, I only get the first-queried results back. So if I call GetInbox(4374) it gives me message A and message B. Calling GetInbox(526) afterwards still gives me message A and B, even though there are messages C and D who do have a userId of 526. I have to restart the application to see any changes.

What's going on here? I'm sure I'm doing something so stupid that I'm going to be ashamed when someone points it out to me. If I'm not doing something very stupid, then I find this issue very strange. I read about not reusing DataContext, but I am not. Why this caching issue? Below is my controller code, but I doubt it matters:

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

Though there are similar questions on SO, I haven't found an answer to this exact question. Many thanks!

UPDATE:
changing the code to: return repo.Messages.ToList().Where(m => m.MessageFrom == userId); fixes it, it works fine then. Seems like some cache problem. However, I of course don't want to fix it that way.
Changing the code so that the datacontext is not disposed after the query does not fix the problem.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

命比纸薄 2024-07-31 03:44:21

我写了一些非常相似的代码,看起来效果很好。 唯一的区别是,正如 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(); ;
        }
    }
}

I wrote some pretty similar code that seems to work fine. The only difference is that as Marc suggests, I'm passing in the connection string and calling ToList on the Where method. My Database is not automatically generated but derives from DataContext. The code is below.

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(); ;
        }
    }
}
江南月 2024-07-31 03:44:21

从编写测试开始。 这将告诉您 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);
}

Start of by writing a test. This will tell you wether Linq2Sql is behaving correctly. Something like:

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);

If that succeeds, you should really check wether it's the deferred execution that's causing problems. You should enumerate inboxMessages right away.

Another thing that might be causing trouble, is the fact that you start enumerating when the datacontext is already disposed. The only way to solve this, is not to dispose it at all (and rely on the GC cleaning it up when it goes out of scope), or come up with a custom IDisposable object, so you can put a using around it. Something like:

using(var inboxMessages = this.messageRepository.GetInbox(userId1))
{
    Assert.That(inboxMessages.All(m => m.MessageTo == userId1);
}
请止步禁区 2024-07-31 03:44:21

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

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

LINQ 的 Where 方法被延迟 - 这意味着它不会执行,直到您迭代数据(例如使用 foreach)。 但到那时你已经处理了数据上下文! 您是否从示例中截取了一些内容?

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

Caching in LINQ-to-SQL is associated with the DataContext, and is mainly limited to identity caching - in most cases it will re-run a query even if you've done it before. There are a few examples, like .Single(x=>x.Id == id) (which has special handling).

Since you are clearly getting a new data-context each time, I don't think that is the culprit. However, I'm also slightly surprised that the code works... are you sure that is representative?

LINQ's Where method is deferred - meaning it isn't executed until you iterate the data (for example with foreach). But by that time you have already disposed the data-context! Have you snipped something from the example?

Also - by giving it a SqlConnection (that you don't then Dispose()), you may be impacting the cleanup - it may be preferable to just give it (the data-context) the connection string.

剧终人散尽 2024-07-31 03:44:21

嗯,看来是DbLinq的问题。 我使用了 3 周前的源代码,QueryCache 中存在一个明显的错误(尽管它总是在那里)。 有一个完整的线程涵盖了这个这里

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

Well, it seemed that it was a problem with DbLinq. I used source code from 3 weeks old and there was an apparant bug in QueryCache (though it has always been in there). There's a complete thread that covers this here.

I updated the dblinq source. Querycache is now disabled (does imply a performance hit) and well at least now it works. I'll have to see if the performance is acceptable. Must confess that I'm a bit baffled though as what I'm trying to do is a common linq2sql pattern. Thanks all.

故事和酒 2024-07-31 03:44:21

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

……你已被警告过!

I'd avoid using DBLinq for production code... many of Linq-To-SQL's features aren't implemented, and walking through the source code shows a low level of maturity... many of the methods are not implemented or marked as "unterminated".

...you've been warned!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文