2009-06-04 2 views
0

Я использую linq для sql для MySql (используя DbLinq) на веб-сайте ASP.NET MVC. У меня странная проблема кэширования. Рассмотрим следующие методы в моем классе Repository:DbLinq - Проблема с кэшем

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, у которых do есть userId из 526. Мне нужно перезагрузить приложение для просмотра любых изменений.

Что здесь происходит? Я уверен, что я делаю что-то настолько глупое, что мне будет стыдно, когда кто-то мне это скажет. Если я не делаю что-то очень глупое, то я считаю эту проблему очень странной. Я читал о том, что не повторно использую DataContext, но я нет. Почему эта проблема кеширования? Ниже мой код контроллера, но я сомневаюсь, что это имеет значение:

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

Хотя есть подобные вопросы на SO, я не нашел ответ на этот точный вопрос. Большое спасибо!

UPDATE: изменения кода на: return repo.Messages.ToList().Where(m => m.MessageFrom == userId); исправляет это, он работает отлично после этого. Похоже на проблему с кешем. Тем не менее, я, конечно, не хочу это исправлять. Изменение кода так, что datacontext не удаляется после запроса не устранить проблему.

+0

Это может показаться глупым, но это не имеет ничего общего с механизмом кэширования Asp.Net? – Micah

+0

Ну, я сначала боялся этого. Но внутри моего класса MailBox я отчетливо вижу пустой IEnumberable . Или один со старыми данными в этом отношении. Так что это не проблема. – Razzie

+0

Если это DbLinq (из вашего комментария), вы должны переименовать и изменить теги; DbLinq может делиться немного ... спрашивать о LINQ-to-SQL не поможет вам ;-p –

ответ

1

Хорошо, похоже, что это была проблема с DbLinq. Я использовал исходный код с 3-х недель, и в QueryCache появилась ошибка apparant (хотя у нее всегда было). Существует полная нить, которая охватывает этот номер here.

Я обновил источник dblinq. Querycache теперь отключен (подразумевает удар производительности) и, по крайней мере, теперь он работает. Я должен посмотреть, приемлемо ли выполнение. Должен признаться, что я немного озадачен, хотя то, что я пытаюсь сделать, это обычный шаблон linq2sql. Спасибо всем.

1

Кэширование в LINQ-to-SQL связано с DataContext и в основном ограничено кешированием идентификаторов - в большинстве случаев оно будет повторно запускать запрос, даже если вы это сделали раньше. Есть несколько примеров, например, .Single(x=>x.Id == id) (который имеет специальную обработку).

Поскольку вы каждый раз получаете новый информационный контекст, я не думаю, что это преступник. Тем не менее, я также немного удивлен, что код работает ... вы уверены, что это представитель?

Метод LINQ's Where отложен - это означает, что он не выполняется до тех пор, пока вы не выполните итерацию данных (например, с foreach). Но к тому времени вы уже настроили контекст данных! Вы что-то отрезали от примера?

Кроме того, предоставив ему SqlConnection (что вы не тогда Dispose()), вы можете повлиять на очистку - может быть предпочтительнее просто дать ему (контексте данных) строку соединения.

+0

Подумайте об этом, это действительно странно. Код является репрезентативным, с небольшим исключением, что у меня было статическое свойство в вспомогательном классе, который возвратил новое SqlConnection. Сгенерированный класс DataContext по SqlMetal (или, в моем случае, DbMetal) дает ему конструктор, который принимает IDbConnection, поэтому я не думал об этом. Возможно, проблема заключается в реализации DbLinq IQueryable.Where (Func ), который для одного не откладывает выполнение? Я посмотрю, что на работе завтра. – Razzie

1

Я написал довольно похожий код, который, кажется, работает нормально. Единственное отличие состоит в том, что, как говорит Марк, я передаю строку соединения и вызываю ToList в методе Where. Моя база данных не создается автоматически, а происходит из 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(); ; 
     } 
    } 
} 
+0

Спасибо, завтра на работе я также дам вызов ToList. В нашем коде мало различий. – Razzie

+0

ToList() приведет к тому, что все последующие операции linq будут выполняться как linq для объектов, вместо преобразования в операторы SQL. Я бы рекомендовал не использовать ToList(), пока не будет веской причины для этого. –

+0

Я знаю, но это нормально в моей ситуации. Я могу, по крайней мере, проверить, если это как-то исправит мою проблему, хотя я предполагаю, что это желаемое решение :-) – Razzie

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

Если это удастся, вы должны действительно проверить, есть ли отложенное выполнение, вызывающее проблемы. Вы должны сразу перечислить входящие сообщения.

Еще одна вещь, которая может вызвать проблемы, заключается в том, что вы начинаете перечислять, когда datacontext уже удален. Единственный способ решить эту проблему - вовсе не избавиться от нее (и полагаться на очистку GC, когда она выходит из сферы действия), или создать собственный объект IDisposable, чтобы вы могли использовать его вокруг. Кое-что вроде:

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

Я бы не использовал DBLinq для производственного кода ... многие функции Linq-To-SQL не реализованы, а прохождение по исходному коду показывает низкий уровень зрелости ... многие из методов не являются реализовано или обозначено как «unterminated».

... вас предупреждают!

+0

вы правы. Я столкнулся с множеством ошибок при использовании DBLinq и многих методов, которые, действительно, не были реализованы. Вскоре после того, как я задал этот вопрос, я переключился с DBLinq на платформу Devart Linq2Sql для MySql, и это намного лучше. У меня было очень мало проблем с этим. К сожалению, это не бесплатно, но, в конце концов, это спасло меня намного больше! – Razzie