实体框架代码第一个现有数据库在多对多上设置EntityState.Unchanged

时间:2014-12-29 19:32:51

标签: c# entity-framework entity-framework-6

我有一个现有的数据库,我正在使用Entity Framework 6 Code First进行编码。我有一个多对多的关系,适用于选择,插入和删除。我在EF为现有关系的多对多表添加额外插入时遇到问题。

架构: enter image description here

的DbContext:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       Database.SetInitializer<MainContext>(null);

       modelBuilder.Entity<DocumentType>()
                .HasMany(u => u.DocumentStatuses)
                .WithMany()
                .Map(m =>
                {
                    m.MapLeftKey("DOCUMENT_TYPE_ID");
                    m.MapRightKey("DOCUMENT_STATUS_ID");
                    m.ToTable("DOCUMENT_TYPES_DOCUMENT_STATUSES");
                });

       base.OnModelCreating(modelBuilder);
    } 

的DTO:

    [Table("DOCUMENT_TYPES")]
    public class DocumentType
    {
        [Key]
        [Column("DOCUMENT_TYPE_ID")]
        public int? Id { get; set; }

        [Required]
        [Column("TYPE_NAME")]
        public string TypeName { get; set; }

        [Required]
        [Column("IS_ACTIVE")]
        public bool IsActive { get; set; }

        [Display(Name = "Updated By")]
        [Column("LAST_UPDATED_BY")]
        public string LastUpdatedBy { get; set; }

        [Display(Name = "Updated Date")]
        [Column("LAST_UPDATED_DATE")]
        public DateTimeOffset? LastUpdatedDate { get; set; }

        public virtual List<DocumentStatus> DocumentStatuses { get; set; } 

        public DocumentType()
        {
            DocumentStatuses = new List<DocumentStatus>();
        }
    }

[Table("DOCUMENT_STATUSES")]
public class DocumentStatus
{
    [Key]
    [Column("DOCUMENT_STATUS_ID")]
    public int? Id { get; set; }

    [Required]
    [Column("STATUS_NAME")]
    public string StatusName { get; set; }

    [Required]
    [Column("IS_COMPLETE")]
    public bool IsComplete { get; set; }

    [Required]
    [Column("IS_ACTIVE")]
    public bool IsActive { get; set; }

    [Display(Name = "Updated By")]
    [Column("LAST_UPDATED_BY")]
    public string LastUpdatedBy { get; set; }

    [Display(Name = "Updated Date")]
    [Column("LAST_UPDATED_DATE")]
    public DateTimeOffset? LastUpdatedDate { get; set; }
}

存储库更新:

    public bool Update(DocumentType entity, string updatedBy)
            {
                DateTimeOffset updatedDateTime = DateTimeOffset.Now;

                entity.LastUpdatedBy = updatedBy;
                entity.LastUpdatedDate = updatedDateTime;

                using (var db = new MainContext())
                {
                    db.DocumentTypes.Add((DocumentType)entity);
                    db.Entry(entity).State = EntityState.Modified;

                    foreach (var item in entity.DocumentStatuses)
                    {
                        if (item.Id != null)
                            db.Entry(item).State = EntityState.Unchanged;
                    }

                    db.SaveChanges();
                }

                return true;
            }

包含以下内容的循环:

    if (item.Id != null)
     db.Entry(item).State = EntityState.Unchanged;

阻止添加新记录,但EF仍尝试在DOCUMENT_TYPES_DOCUMENT_STATUSES中插入现有多对多记录的副本。

单元测试:

        [TestMethod()]
        public void UpdateTest()
        {
            DocumentTypeRepository documentTypeRepository = new DocumentTypeRepository();
            DocumentType type = NewDocumentType(true);
            DocumentType typefromDb;
            string updatedBy = "DocumentTypeRepositoryTests.UpdateTest";
            bool actual;

            type.IsActive = true;
            type.TypeName = RandomValues.RandomString(18);
            type.DocumentStatuses.Add(DocumentStatusRepositoryTests.NewDocumentStatus(true));

            actual = documentTypeRepository.Update(type, updatedBy);
            Assert.AreEqual(true, actual);

            typefromDb = documentTypeRepository.GetById((int)type.Id);
            Assert.AreEqual(type.DocumentStatuses.Count, typefromDb.DocumentStatuses.Count);
        }

如果已经存在,那么如何将多对多表设置为EntityState.Unchanged?

2 个答案:

答案 0 :(得分:1)

尝试替换

db.DocumentTypes.Add((DocumentType)entity);
db.Entry(entity).State = EntityState.Modified;

db.Entry(entity).State = entity.Id == null 
    ? EntityState.Added
    : EntityState.Modified;

使用分离的实体执行CRUD操作时,更容易不使用DbSet操作并仅操纵实体状态条目。至少,它可以减少错误。

答案 1 :(得分:1)

这里有两件事需要注意:

  1. 当您将Add实体添加到上下文时,该实体拥有的整个对象图标记为Added

  2. 在任何关联中,这也将协会标记为新的。但是,在1:n或1:1关联中,当其中一个结束的状态发生变化时,关联状态会发生变化,在多对多关联中,有一部分关联被隐藏,并且总是保持Added。 (引擎盖下的多对多关联是1:n:1关联,n部分在您的代码中不可见。

  3. 所以这句话......

    db.DocumentTypes.Add(entity);
    

    导致关联获得Added状态,以及随后的......

    db.Entry(entity).State = EntityState.Modified;
    

    不再对此进行更改。

    您必须确保对于现有DocumentType状态永远不会更改为Added,您可以通过检查其Id值来执行此操作,与DocumentStatus相同1}}。

    此外,您必须更改设置DocumentStatuses的状态:

    foreach (var item in entity.DocumentStatuses)
    {
        db.Entry(item).State = item.Id != null
                                   ? EntityState.Unchanged
                                   : EntityState.Added;
    }