开发者

Entity Framework Code First Update Does Not Update Foreign Key

I'm using EF 4.1 Code First. I have an entity defined with a property like this:

public class Publication 
{
    // other stuff
    public virtual MailoutTemplate Template { get; set; }
}

I've configured this foreign key using fluent style like so:

    modelBuilder.Entity<Publication>()
        .HasOptional(p => p.Template)
        .WithMany()
        .Map(p => p.MapKey("MailoutTemplateID"));

I have an MVC form handler with some code in it that开发者_运维问答 looks like this:

public void Handle(PublicationEditViewModel publicationEditViewModel)
        {
            Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
            publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
            if (publication.Id == 0)
            {
                _publicationRepository.Add(publication);
            }
            else
            {
                _publicationRepository.Update(publication);
            }
            _unitOfWork.Commit();
        }

In this case, we're updating an existing Publication entity, so we're going through the else path. When the _unitOfWork.Commit() fires, an UPDATE is sent to the database that I can see in SQL Profiler and Intellitrace, but it does NOT include the MailoutTemplateID in the update.

What's the trick to get it to actually update the Template?

Repository Code:

public virtual void Update(TEntity entity)
{
    _dataContext.Entry(entity).State = EntityState.Modified;
}

public virtual TEntity Get(int id)
{
    return _dbSet.Find(id);
}

UnitOfWork Code:

public void Commit()
{
    _dbContext.SaveChanges();
}


depends on your repository code. :) If you were setting publication.Template while Publication was being tracked by the context, I would expect it to work. When you are disconnected and then attach (with the scenario that you have a navigation property but no explicit FK property) I'm guessing the context just doesn't have enough info to work out the details when SaveChanges is called. I'd do some experiments. 1) do an integration test where you query the pub and keep it attached to the context, then add the template, then save. 2) stick a MailOutTemplateId property on the Publicaction class and see if it works. Not suggesting #2 as a solution, just as a way of groking the behavior. I"m tempted to do this experiment, but got some other work I need to do. ;)


I found a way to make it work. The reason why I didn't initially want to have to do a Get() (aside from the extra DB hit) was that then I couldn't do this bit of AutoMapper magic to get the values:

Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);

However, I found another way to do the same thing that doesn't use a return value, so I updated my method like so and this works:

    public void Handle(PublicationEditViewModel publicationEditViewModel)
        {
            Publication publication = _publicationRepository.Get(publicationEditViewModel.Id);
            _mappingEngine.Map(publicationEditViewModel, publication);
//            publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
            publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
            if (publication.Id == 0)
            {
                _publicationRepository.Add(publication);
            }
            else
            {
                _publicationRepository.Update(publication);
            }
            _unitOfWork.Commit();
        }

I'm injecting an IMappingEngine now into the class, and have wired it up via StructureMap like so:

    For<IMappingEngine>().Use(() => Mapper.Engine);

For more on this, check out Jimmy's AutoMapper and IOC post.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜