Как правильно использовать объект LINQ2SQL DataContext;создавая заново каждое использование вызывает головные боли - PullRequest
2 голосов
/ 24 февраля 2011

Итак, изучая LINQ2SQL (не говорите, что это мертвая технология, пожалуйста, я не переключаюсь на EF для простых приложений) Я много раз читал, что класс DataContext предназначен для частого создания и уничтожения. Отлично, легкий объект, который я могу использовать для доступа к своей базе данных. Однако на практике это, кажется, не вызывает никаких проблем. Например, если я загружаю DataGrid таким образом, изменения объектов сущности, кажется, не отслеживаются, и вызов DataContext.SubmitChanges не имеет никакого эффекта:

void LoadUI()
{
    using( var db = new TestDataContext() )
    {
        // use DataLoadOptions.LoadWith<T> if we need 
        // access to foreign key/ deferred objects.
        masterGrid.ItemsSource = db.Customers.ToList();
        detailsGrid.ItemsSource = // this is always set to a collection of Settings
                                  // for the currently selected user in masterGrid.
                                  // just a simple foreign key relationship
    }
}

void UpdateName( string newName )
{
    using( var db = new TestDataContext() )
    {
        var customer = ((Customer)masterGrid.SelectedItem);
        customer.Name = newName;
        db.SubmitChanges() // !!! database is not updated !!!    
    }
}

Так что же дает? Создание нового объекта DataContext при доступе к БД представляется приемлемой / предпочтительной практикой, но, похоже, не работает в самых тривиальных случаях. Похоже, что отслеживание объектов не работает в этом сценарии, так как же можно использовать класс DataContext, как это на практике? Я что-то здесь упускаю? (Примечание: я действительно надеюсь, что мне не хватает чего-то простого.

Я должен предположить, что это так, но я пока не знаю, каков ответ. В настоящее время я просто держу один DC для жизни приложения, что, я знаю, не очень хорошая идея). Заранее благодарим за любой совет, который вы можете предложить.

Кстати, если кто-нибудь из вас знает исчерпывающую статью / серию статей, в которых описываются входы и выходы класса DataContext, я бы с удовольствием его прочитал. Я не нашел примеров, которые выходят за рамки тривиальных обновлений / вставок / удалений.

Ответы [ 3 ]

2 голосов
/ 24 февраля 2011

Ответ в том, что у вас есть 2 способа (и намного больше!), Чтобы решить эту проблему.

Экземпляр объекта в вашей сетке принадлежит DataContext # 1. В вашем методе UpdateName вы создаете новый DataContext # 2. Как DataContext # 2 может знать, что объект из DataContext # 1 изменился? Никогда. Итак: Используйте DataContext # 2 для извлечения объекта Customer из базы данных и используйте полученный объект для изменения свойства.

Другой способ - использовать DTO. Этот способ еще долго описывать, но принцип в том, что вы создаете класс, у которого есть все свойства, которые есть у клиента, но больше ничего (=> этот класс больше не связан с вашим DataContext), и после изменения свойств вы переподключаетесь класс в свой DataContext и сохранить его.

Надеюсь, я смогу вам помочь.

void LoadUI()
{
    using( var db = new TestDataContext() )
    {
        // use DataLoadOptions.LoadWith<T> if we need 
        // access to foreign key/ deferred objects.
        masterGrid.ItemsSource = db.Customers.ToList();
        detailsGrid.ItemsSource = // this is always set to a collection of Settings
                                  // for the currently selected user in masterGrid.
                                  // just a simple foreign key relationship
    }
}

void UpdateName( string newName )
{
    using( var db = new TestDataContext() )
    {
        var customer = ((Customer)masterGrid.SelectedItem);
        var freshLoadedCustomer = db.Customers.FirstOrDefault(cust=>cust.Id == customer.Id);
        if(freshLoadedCustomer != null)
        { freshLoadedCustomer.Name = newName; db.SubmitChanges();}
    }
}
1 голос
/ 24 февраля 2011

Волшебные слова - «Связывание данных».Это то, что вам нужно для отображения данных, а также то, что вам нужно для сохранения данных обратно в базу данных.

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

Самым простым решением может быть создание доступного для записипуть данных для вашей сетки данных, а не пытаться отслеживать и сохранять изменения из сетки данных вручную.Есть несколько способов сделать это.Один из известных мне способов заключается в использовании ObservableCollection. ObservableCollection предоставляет уведомления, когда элементы добавляются, удаляются или когда обновляется весь список.Это позволяет вам привязать код к этим событиям, чтобы обеспечить функцию сохранения.

Однако изначально вашей лучшей ставкой может быть этот поиск.

1 голос
/ 24 февраля 2011

Измененные объекты могут быть обновлены только с помощью текста данных, с которым они были созданы.Текст данных обычно создается один раз для каждой единицы работы (например, страницы или формы, которые получают некоторые объекты, что-то с ними делают и обновляют их в БД).

РЕДАКТИРОВАТЬ 2, В ответ на комментарий FooWombat:Для более реального примера прочитайте Datacontext Lifetime Management в блоге Рика Строля.Я подробно расскажу, как реализовать обработку текста данных, чтобы все происходило за кулисами, и вы можете выбирать / обновлять / удалять объекты linq2sql, не задумываясь об этом.

РЕДАКТИРОВАТЬ 1: Кроме того, если вы немного погуглите, вы также найдете метод под названием Attach .Этот метод предназначен для использования с объектами, которые были десериализованы и затем сериализованы обратно.Упоминается, что не следует пытаться прикрепить объекты из другого текста данных.Однако в этом blogpost у вас есть пример (ab) использования Attach, чтобы вы точно могли это сделать.Я бы использовал его, только если вы в затруднении и вам действительно нужно переносить объекты из одного текстового контекста в другой.Это не очень рекомендуемая практика.

Из блога:

public partial class Employee
{
   public void Detach()
   {
       this.PropertyChanged = null; this.PropertyChanging = null;
       // Assuming there's a foreign key from Employee to Boss
       this.Boss = default(EntityRef<Boss>);
       // Similarly set child objects to default as well
       this.Subordinates = default(EntitySet<Subordinate>);
   }
}

Вы можете использовать этот метод Detach, чтобы сделать это:

public static void UpdateEmployee(Employee employee)
{
    using (HRDataContext dataContext = new HRDataContext())
    {
        //attach to datacontext
        employee.Detach();
        dataContext.Employees.Attach(employee);
        //save changes
        dataContext.SubmitChanges();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...