EF不更新相关实体,只更新简单字段

时间:2015-04-21 18:20:08

标签: c# .net entity-framework mapping

我在EF 6.1中使用codeFirst和独立协议 EF不会更新分离的实体。 Attach和StateModified对Related(FK)实体没有帮助。 添加新实体和提升非相关属性可正常工作。 问题在哪里?

我有主要实体CoachTransaction:

public class CoachTransaction : BaseEntity
    {
        public DateTime? TransactionDate { get; set; }

        public int? Season { get; set; }
        public virtual CoachPosition Position { get; set; }
        public virtual Institution StartInstitution { get; set; }
        public virtual Institution EndInstitution { get; set; }       
    }

映射:

public MapCoachTransaction()
        {
            ToTable("CoachTransactions");
            HasKey(x => x.Id);

            Property(x => x.Id).HasColumnName("TransactionId");
            Property(x => x.TransactionDate);

            HasOptional(x => x.Position).WithMany().Map(x => x.MapKey("CoachPositionId"));
            HasOptional(x => x.StartInstitution).WithMany().Map(x => x.MapKey("StartInstitutionId"));
            HasOptional(x => x.EndInstitution).WithMany().Map(x => x.MapKey("EndInstitutionId"));
        }

相关实体如下所示:

 public class Institution : BaseEntity
    {
        public virtual InstitutionType InstitutionType { get; set; }
        public string Name { get; set; }
        public string ImageUrl { get; set; }        
    }

相关实体的映射:

 public MapInstitution()
        {
            ToTable("Institution");
            HasKey(x => x.Id);
            Property(x => x.Id).HasColumnName("InstitutionId");
            HasOptional(x => x.InstitutionType).WithMany(x => x.Institutions).Map(x => x.MapKey("InstitutionTypeId"));
            Property(x => x.Name).HasColumnName("InstitutionName");
            Property(x => x.ImageUrl).HasColumnName("InstitutionImageUrl");
        }

用法如下:

                using (var context = new CoachDBContext())
                {
                    IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
                   coachTransaction.Seasion = 100; // this works
                    coachTransaction.EndInstitution = newInstitution; this doesnt'
                    repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
                    repository.Save();
                }

和repository.Updarte方法使用附件:

public virtual void Update(TEntity entityToUpdate)
        {
            EntitySet.Attach(entityToUpdate);
            dbContext.Entry(entityToUpdate).State = EntityState.Modified;
        }

使用此设置,SQL请求如下所示:

exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1
WHERE ([TransactionId] = @2)
',N'@0 datetime2(7),@1 int,@2 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=24

因此,我的endInstitution实体没有更新。

但如果我在保存前请求此实体:

  using (var context = new CoachDBContext())
                    {
                        IGenericRepository<CoachTransaction> repository = new GenericRepository<CoachTransaction>(context);
                        var coachTransaction = repository.GetById(coachTransaction.Id) // this fixes problem, but not acceptable in this case
                        coachTransaction.Season = 100; 
                        coachTransaction.EndInstitution = newInstitution; // now this will work
                        repository.Update(coachTransaction); // coachTransaction comes from POST to Controller
                        repository.Save();
                    }

SQL将包含相关键,如:

exec sp_executesql N'UPDATE [dbo].[CoachTransactions]
SET [TransactionDate] = @0, [Season] = @1, 

[EndInstitution] = @2

WHERE ([TransactionId] = @3)
',N'@0 datetime2(7),@1 int,@2 int, @3 int',@0='2015-04-21 20:40:38.1840996',@1=100,@2=2,@3=24

P.S。

另外,使用Foreignkey assosiation approeach通过这样的映射修复了这个问题:

Property(x => x.PositionId).HasColumnName("CoachPositionId");
            Property(x => x.StartInstitutionId).HasColumnName("StartInstitutionId");
            Property(x => x.EndInstitutionId).HasColumnName("EndInstitutionId");
            HasRequired(x => x.Position).WithMany().HasForeignKey(x => x.PositionId);
            HasRequired(x => x.StartInstitution).WithMany().HasForeignKey(x => x.StartInstitutionId);
            HasRequired(x => x.EndInstitution).WithMany().HasForeignKey(x => x.EndInstitutionId);

但它导致另一个问题,当我必须设置两个属性而不是一个更新相关实体时,如:

updatingObject.EndInstitution = existingInstitution2; 
updatingObject.EndInstitutionId = existingInstitution2.Id;

一个电话:     updatingObject.EndInstitution = existingInstitution2;

此外,它还需要无用的Id属性。从我的角度来看,这看起来不对。 有一些解决方案吗?

1 个答案:

答案 0 :(得分:4)

Attach方法不附加子实体。为此,您需要附加要更新的所有依赖项目标。 您可以使用GraphDiff更新完整图表,而无需附加实体。用法是这样的: 使用(var con

text = new TestDbContext())  
{
    // Update the company and state that the company 'owns' the collection Contacts.
    context.UpdateGraph(company, map => map
        .OwnedCollection(p => p.Contacts, with => with
            .AssociatedCollection(p => p.AdvertisementOptions))
        .OwnedCollection(p => p.Addresses)
    );

    context.SaveChanges();
}

这是框架的brief introduction

此外,我一直在审查实体框架的源代码,如果您知道另一种情况下需要检查AddOrUpdate实现的Key属性,则找到实际更新实体的方法:

public void Update(T item)
{
    var entity = _collection.Find(item.Id);
    if (entity == null)
    {
        return;
    }

    _context.Entry(entity).CurrentValues.SetValues(item);
}

希望这有帮助!