Как обновить новую запись, прежде чем она будет зафиксирована в EF4? - PullRequest
1 голос
/ 19 марта 2011

Я использую EF4 POCO и шаблоны UnitOfWork / репозиторий с MVC 3. Я пытаюсь понять, как мне изменить новую запись, которая должна быть вставлена.

Мой метод службы для вставки / обновления выглядит примерно так (хранилище внедряется в конструктор службы через IoC):

public void UpdateData(Guid id, int newValue)
{
    MyPoco poco = _repository.FirstOrDefault(p => p.Id = id);

    if (poco == null)
    {
        poco = new Poco 
        {
            //set properties
        };

        _repository.Add(poco);
    }

    poco.SomeFieldToUpdate = newValue;
}

И мои изменения сохраняются через мой UnitOfWork в фильтре действий UseUnitOfWorkAttribute на моем контроллере:

void IResultFilter.OnResultExecuted(ResultExecutedContext filterContext)
{
    var unitOfWork = IoCFactory.Instance.CurrentContainer.Resolve<IUnitOfWork>();
    unitOfWork.Commit();
}

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

Но если значение Guid не существует в таблице, оно пытается выполнить несколько вставок, если оно вызывается несколько раз.

Так что это моя дилемма. Я понимаю, почему это не работает, я просто не уверен, как это исправить. По сути, мне нужно как-то получить ссылку на существующий POCO в UnitOfWork и как-то обновить его. Но UnitOfWork недоступен в моем сервисе (по замыслу) - и я даже не уверен, что знаю, как вытащить объект из UoW и обновить его в любом случае.

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

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 19 марта 2011

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

Вам не нужно использовать репозиторий / единицу работы / ObjectContex в качестве внутреннего хранилища несохраненных сущностей среди вызовов служб.Если вам это нужно, вы должны проверить дизайн своего приложения и реорганизовать его, потому что, возможно, что-то не так.

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

public MyPoco GetById(Guid id)
{
    MyPoco enity = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added)
        .Where(e => e.Entity != null && e.Entity.GetType() == typeof(MyPoco)))
        .Select(e => (MyPoco)e.Entity)
        .Where(p => p.Id == id)
        .SingleOrDefault();

    if (entity == null)
    {
        entity = context.MyPocos.FirstOrDefault(p => p.Id == id);
    }
}
0 голосов
/ 19 марта 2011

Вы устанавливаете идентификатор, который вы передаете в UpdateData в качестве ключа для нового объекта Poco, например:

poco = new Poco 
{
    Id = id;
    //set properties
};

Если да, вы можете запросить объект не с FirstOrDefault, а сиспользуя TryGetObjectByKey в методе хранилища:

public Poco GetPocoByKey(Guid id)
{
    EntityKey key = new EntityKey("MyEntities.Pocos", "Id", id);
    object pocoObject;
    if (context.TryGetObjectByKey(key, out pocoObject))
        return (Poco)pocoObject;

    return null;
}

Преимущество заключается в том, что TryGetObjectByKey сначала смотрит в ObjectContext, если он может найти объект с указанным ключом.Только если нет, то база данных будет запрашиваться.Поскольку вы добавляете новое Poco в контекст в первый раз, когда он не найден, TryGetObjectByKey должен найти его в контексте при повторном поиске объекта с тем же ключом, даже если он еще не был сохранен в базе данных..

Редактировать: Это решение не работает!

Поскольку TryGetObjectByKey не находит ключ для объектов, которые находятся в состоянии added в ObjectContext,даже если ключ не является ключом, сгенерированным БД и предоставленным приложением (см. комментарии ниже).

...