Вопрос

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

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

Что происходит, так это то, какой бы из двух методов я ни вызывал, с каким бы идентификатором пользователя результаты остаются неизменными.Точка.Даже несмотря на то, что я вижу, что repo.Messages имеет более 10 результатов с различной MessageFrom и MessageTo значения, я получаю обратно только результаты первого запроса.Так что, если я позвоню GetInbox(4374) это дает мне сообщение A и сообщение B.Зовущий GetInbox(526) впоследствии все еще выдает мне сообщения A и B, даже несмотря на то, что там являются сообщения C и D, которые делай имейте идентификатор пользователя 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 не удалялся после выполнения запроса не устраните проблему.

Это было полезно?

Решение 4

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

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

Другие советы

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

Начните с написания теста.Это подскажет вам, правильно ли работает 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);
}

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

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

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

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

Я бы предпочел не использовать DbLinq для производственного кода...многие функции Linq-To-SQL не реализованы, а ознакомление с исходным кодом показывает низкий уровень зрелости...многие из методов не реализованы или помечены как "незавершенные".

...вы были предупреждены!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top