Linq to Sql - Как обновить объект с помощью шаблона хранилища? - PullRequest
1 голос
/ 30 января 2011

Существует масса информации по этому вопросу, но даже после чтения в течение многих часов я, кажется, не могу заставить это работать так, как я хочу.

Я пытаюсь обновить объект User, передавая объект User и сравнивая изменения, внесенные в объект User, который я извлекаю из базы данных. Я всегда получаю NotSupportedException при использовании этого метода:

Была предпринята попытка присоединить или Возможно, добавьте объект, который не является новым будучи загруженным из другого DataContext. Это не поддерживается.

Вот как я пытаюсь это сделать:

    public void SaveUser(User User)
    {
        using (DataContext dataContext = new DataContext(WebConfigurationManager.ConnectionStrings["database"].ConnectionString))
        {
            // New user
            if (User.UserID == 0)
            {
                dataContext.Users.InsertOnSubmit(User);
            }
            // Existing user
            else
            {
                User dbUser = dataContext.Users.Single(u => u.UserID.Equals(User.UserID));
                Type t = dbUser.GetType();
                foreach (PropertyInfo p in t.GetProperties())
                {
                    if (p.CanWrite & p.GetValue(dbUser, null) != p.GetValue(User, null))
                    {
                        p.SetValue(dbUser, p.GetValue(User, null), null);
                    }
                }
                //dataContext.Refresh(RefreshMode.KeepCurrentValues, dbUser);
            }
            dataContext.SubmitChanges();
        }
    }

Закомментированная строка, которую я тоже пробовал без комментариев, но это не помогло.

Если я закомментирую цикл foreach () и добавлю строку вроде dbUser.UserName = "Cheese"; Это обновит имя пользователя в базе данных штрафа. Это заставляет меня поверить, что это связано с тем, что цикл foreach () изменяет объект dbUser, что приводит к сбою.

Когда я отлаживаю объект dbUser, он, по-видимому, корректно получает все изменения от объекта User, переданного в качестве аргумента.

Я также немного прочел оптимистичный параллелизм и добавил столбец в таблицу меток времени типа данных, но, похоже, это тоже не имело никакого эффекта.

Что именно я здесь не так делаю?

Как я могу получить это для общего обнаружения того, что изменилось, и правильно сохранить изменения в базе данных?

Ответы [ 2 ]

2 голосов
/ 30 января 2011

Я предполагаю, что есть отношение внешнего ключа, которое вы пытаетесь скопировать, которое не было изначально загружено (из-за отложенной загрузки) Во время копирования оно пытается загрузить его, но DataContext уже был удален.

Я работал над похожей проблемой. В итоге я использовал AutoMapper для копирования своих свойств. Я настроил AutoMapper, чтобы игнорировать поле первичного ключа, а также любые отношения. Что-то вроде:

public void Update(User user)
{
     using (var db = new DataContext(...))
     {
         var userFromDb = db.Users.Where(x => x.Id == user.Id).Single();
         AutoMapper.Mapper.Map(user, userFromDb);
         db.SubmitChanges();
    }
}

Моя конфигурация автопроизводителя похожа на

AutoMapper.Mapper.Create<User, User>().ForMember(dest => dest.Id, opt => opt.Ignore())
                                      .ForMember(dest => dest.SomeRelation, opt => opt.Ignore());

Вы можете найти AutoMapper здесь: http://automapper.codeplex.com/

0 голосов
/ 30 января 2011

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

public class EventRepository : IEventRepository
{

    private DBDataContext dc;
    public EventRepository()
    {
        dc = new DBDataContext();
    }

    public void Create(Event @event)
    {
        dc.Events.InsertOnSubmit(@event);
    }

    public System.Linq.IQueryable<Event> Read()
    {
        object events = (from e in dc.Eventse);
        return events.AsQueryable;
    }

    public void SubmitChanges()
    {
        dc.SubmitChanges();
    }

}

Тогда соответствующий вызов из сервисного уровня выглядит следующим образом

public void AddEvent(Event @event)
{
    _EventRepository.Create(@event);
}

public void SubmitChanges()
{
    _EventRepository.SubmitChanges();
}

И я звоню с моего контроллера.

// AutoMapper will allow us to map the ViewModel with the DomainModel
Mapper.CreateMap<Domain.ViewModels.EventsAddViewModel, Domain.Event>();
object @event = Mapper.Map<Domain.ViewModels.EventsAddViewModel, Domain.Event>(eventToAdd);

// Add the event to the database
EventService.AddEvent(@event);
EventService.SubmitChanges();
...