我在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个,但MessageFrom
和MessageTo
值不同,我只会得到第一个查询结果。因此,如果我拨打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 不解决问题。
答案 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的功能都没有实现,并且遍历源代码显示成熟度很低......许多方法都没有实现或标记为“未终止”。
......你被警告了!