2011-10-11 70 views
0

我使用EF 4.1代码优先。我有一个属性是这样定义的实体:实体框架代码第一次更新不会更新外键

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

我用流利的风格像这样配置本外键:我有一些代码的MVC表单处理程序在它

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

那看起来像这样:

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(); 
     } 

在这种情况下,我们正在更新现有的出版物实体,所以我们正在经历其他路径。当_unitOfWork.Commit()触发时,UPDATE发送到SQL Profiler和Intellitrace中可以看到的数据库,但它不包含更新中的MailoutTemplateID。

让它实际更新模板有什么窍门?

库代码:

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

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

的UnitOfWork代码:

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

如果很重要,MailoutTemplateID不会在开始时设置。 – ssmith

+0

尝试将'publication.Template = ...'这一行移动到'... Commit'之前的方法底部。变更检测可以确认,然后希望更改模板并将ID发送到数据库。将状态设置为'Modified'对'MailoutTemplateID'列没有影响,因为它不是模型中的标量属性。 – Slauma

回答

1

取决于你的资料库代码。 :)如果您正在设置publication.Template,同时正在按上下文跟踪出版物,则我预计它会起作用。当你断开连接,然后附上(与你有一个导航属性,但没有明确的FK属性的场景),我猜测上下文只是没有足够的信息来调用SaveChanges被调用时的细节。我会做一些实验。 1)进行集成测试,查询pub并将其保存到上下文中,然后添加模板,然后保存。 2)在Publicaction类上粘贴一个MailOutTemplateId属性,看它是否有效。不建议将#2作为解决方案,只是作为一种分散行为的方式。我试图做这个实验,但得到了一些我需要做的其他工作;)

+0

我用Repo和UoW代码更新了问题。问题是我没有在发布中执行Get(),但只是将它与视图模型进行映射?所有其他字段更新正确 - 只有这个FK ID不是。 – ssmith

0

我找到了一种方法来使它工作,之所以我最初并不想要做一个Get( )(除了额外的DB命中)是,那么我不能做的AutoMapper魔术这一点得到的值:

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

然而,我发现另一种方式来做到这一点不使用同样的事情一个返回值,所以我更新了我的方法,像这样和这个作品:

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(); 
     } 

我现在注入IMappingEngine成类,并已通过StructureMap有线起来就像这样:

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

更多关于这一点,看看Jimmy's AutoMapper and IOC post

+0

嗯,当你知道它立即解决你的问题时,为什么你必须等待2天才能将自己的答案标记为答案?就像我真的会记得在两天内回到这里?在接下来的两天里还有多少潜在的回答者会浪费时间呢? – ssmith

+0

你可以在这种情况下完全删除你的'Update'方法(else块)。 '_mappingEngine.Map ...'将设置加载的(=附加的)'出版物'的属性。当你调用'SaveChanges'时,UPDATE语句将被发送到仅包含实际已经改变的属性的DB。 (将状态设置为'Modified'将导致对* all *属性的UPDATE - 无论它们是否真的发生了更改。) – Slauma

相关问题