Как использовать только идентификаторы для сторонней таблицы вместо полных объектов при вставке / обновлении? - PullRequest
1 голос
/ 19 мая 2011

Моя программа более сложная, но в основном проблема в следующем: есть таблица Customer и таблица City. В Customor у меня есть поле cityId и внешний ключ для него.

Теперь я могу написать такой код

customer.cityIdCity = myCity;

или

customer.cityId = 7;

Проблема в том, что я не могу использовать первую форму, потому что города кэшируются, и в этом случае данные будут «захвачены» текущим контекстом данных (и возникнет исключение), поэтому я предпочитаю использовать вторую форму. Однако, когда я отправляю изменения для клиента, я получаю исключение о несоответствии в данных - что честно говоря - cityId равно 7, но cityIdCity равно нулю.

Вопрос - для второй формы, как заставить LINQ сосредоточиться на идентификаторе (и выполнить простую вставку с использованием идентификатора) и принять пропущенный объект.

редактирует

1

Поле cityId является просто int (как в таблице), но sqlmetal также создал другое свойство для класса отображения cityIdCity, которое является ссылкой на класс City (из таблицы City).

Внутренне это выглядит так:

    private EntityRef<City> _cityIdCity;

Существует также длинное свойство cityIdCity, которое устанавливает указанное поле и обрабатывает запуск событий для изменения и изменения состояния поля.

И регулярное поле (int) определяется так:

    private System.Nullable<int> _cityId;

плюс аналогичное свойство.

2

Я обнаружил, что это связано с получением данных. После загрузки данных (в данном случае это объект city для клиента), Linq To SQL предполагает, что оно fixed , т. Е. Идентификатор и ссылка на город должны быть синхронизированы. Если вы не читаете их до изменения, это нормально, потому что L2S устанавливает новые значения, но также извлекает новые данные из БД на лету.

И я должен прочитать город покупателя, прежде чем изменить его.

3

Шаги следующие:

  1. найти в БД клиента
  2. его не существует? -> создать запись
  3. совпадает ли город клиента с входящими данными (город)? если да, перейдите к шагу (8)
  4. проверьте в кеше, если у нас есть соответствующий город, если да, перейдите к (7)
  5. создать запись города
  6. сохранить город
  7. связать город и клиента
  8. сохранить клиента

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

Для сравнения я протестировал несколько случаев с использованием Entity Framework, и он ведет себя более просто, то есть нет проблем в обоих подходах (при изменении ссылочного поля с целым объектом или просто идентификатором).

4

Это упрощенный код, но показывает проблему.

using (var Db = new L2S.DataClasses1DataContext())
{
    var customer = Db.Customers.Single(it => it.cust_Id==2);
    customer.Name = "New name";
    Console.WriteLine(customer.City.city_Name); // loading city from DB
    // cannot change, because we would be out of sync with referenced object
    customer.city_Id = 57834; 

    Db.SubmitChanges();
}

5 - тонкий или жирный контекст данных

Используя тот же пример, что и Pleun. Это жирный ДК:

using (var Db = new L2S.DataClasses1DataContext())
{    
   ...
   customer.City = Db.Cities.Single (i=> i.id =   57834 ); 
   Db.SubmitChanges();
 }

потому что, как вы можете видеть, клиент использует тот же DC, что и города (города кэшируются!). Это неправильно, потому что все искаженные данные от клиента будут перетекать в DC (кеш). Так что ошибка часа назад тоже будет присутствовать.

Это тонкий DC:

var city = CacheDb.Cities.Single (i=> i.id =   57834 ); 

...

using (var Db = new L2S.DataClasses1DataContext())
{    
   ...
   customer.City = city; 
   Db.SubmitChanges();
 }

Однако это не будет работать, потому что L2S не позволяет совместно использовать объекты между DC (в типичном случае между кешем и работающим - обновление - DC).

1 Ответ

0 голосов
/ 19 мая 2011

Вы пробовали

using (var Db = new L2S.DataClasses1DataContext())
{    
 ...
 // leave out customer.city_Id = 57834;  but replace with
 customer.City = Db.Cities.Single (i=> i.id =   57834 ); 
 Db.SubmitChanges();
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...