Добавление другого ответа в качестве комментария недостаточно для расширения моего предыдущего ответа.
Давайте сделаем шаг назад и посмотрим, что вы хотите здесь сделать с логической точки зрения. Вы хотите сообщить своему слою доступа к данным, как он должен обновлять базу данных со всеми новыми / измененными значениями, которые он должен записать.
Один из наиболее распространенных способов сделать это - передать объект, в котором есть эти изменения (именно это вы делаете в своем примере). Это может быть сложно, как вы видели, потому что если вы просто перезапишите переменную сущности с измененной сущностью, Linq2Sql потеряет отслеживание изменений ... только потому, что новая сущность назначена той же переменной, не означает, что Linq2Sql автоматически получает изменения от нового объекта ... фактически Linq2Sql вообще не знает о новом объекте ...
Пример:
// In domain layer:
MyEntity entity = new MyEntity();
entity.PrimaryKey = 10;
entity.Name = "Toby Larone";
entity.Age = 27;
myDataRepository.Update(entity);
// In data layer:
void Update(MyEntity changedEntity)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == changedEntity.PrimaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
entity = changedEntity;
// Linq2Sql does **not** have change tracking of changedEntity - the fact that it has been assigned to the same variable that once stored a tracked entity does not mean that Linq2Sql will magically pick up the changes...
db.SubmitChanges(); // Nothing happens - as far as Linq2Sql is concerned, the entity that was selected in the first query has not been changed (only the variable in this scope has been changed to reference a different entity).
}
}
Теперь вы уже видели, что назначение каждого поля сущности, а не ее замена работает как задумано - это потому, что изменения вносятся в исходную сущность, которая все еще находится в системе отслеживания изменений Linq2Sql.
Одним из возможных решений этой проблемы было бы написание метода, который «применяет» изменения другой сущности к существующей, то есть:
partial class MyEntity
{
void ApplyChanges(MyEntity changedEntity)
{
this.PrimaryKey = changeEntity.PrimaryKey;
this.Name = changedEntity.Name;
this.Age = changedEntity.Age;
}
}
и тогда ваш доступ к данным будет выглядеть так:
// In data layer:
void Update(MyEntity changedEntity)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == changedEntity.PrimaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
entity.ApplyChanges(changedEntity);
db.SubmitChanges(); // Works OK...
}
}
Но я уверен, что вам не понравится это решение - потому что все, что вы сделали, - это фактически переместили повторяющееся назначение полей из хранилища в сам класс Entity ...
Возвращаясь к логической перспективе - все, что вам действительно нужно, это сообщить хранилищу доступа к данным 2 вещи - 1) какую запись вы хотите обновить и 2) каковы изменения. Отправка совершенно новой сущности, которая объединяет эти два требования, не является необходимой для достижения этой цели, на самом деле, я думаю, что это очень неэффективно.
В следующем примере вы отправляете в хранилище данных только изменений, а не всю сущность. Поскольку нет сущности, нет проблем с отслеживанием изменений, чтобы обойти
* +1025 * Пример:
// In domain layer:
myDataRepository.Update(10, entity =>
{
entity.Name = "Toby Larone";
entity.Age = 27;
});
// In data layer:
void Update(int primaryKey, Action<MyEntity> callback)
{
using (var db = new DataContext())
{
var entity = (from e in db.MyEntities
where e.PrimaryKey == primaryKey
select e).First();
// Linq2Sql now has change tracking of "entity"... any changes made will be persisted when SubmitChanges is called...
// The changes that were sent are being applied directly to the Linq2Sql entity, which is already under change tracking...
callback(entity);
db.SubmitChanges();
}
}
В предыдущих примерах назначения полей происходили дважды - один раз, когда вы описывали изменения, которые вы хотели внести, и снова в хранилище данных, когда вам нужно было применить эти изменения к объекту отслеживания изменений Linq2Sql.
Используя обратный вызов, назначения полей происходят только один раз - описание самого изменения - это то, что обновляет отслеживаемую сущность.
Надеюсь, я объяснил это достаточно хорошо:)