C# EF 6代码首先,使用“包含在导航上”属性更改外键Id会导致;发生引用完整性约束冲突";错误

C# EF 6代码首先,使用“包含在导航上”属性更改外键Id会导致;发生引用完整性约束冲突";错误,c#,entity-framework,ef-code-first,entity-framework-6,dbcontext,C#,Entity Framework,Ef Code First,Entity Framework 6,Dbcontext,我使用的是Entity Framework 6.1.3,在这种情况下,我检索具有导航属性的实体(使用Include())并将其与上下文断开连接,更改外键Id,然后将其重新附加到新的DbContext: // Init the Db using (var db = new MyContext()) { var theWarranty = new ProductWarranty { WarrantyName = "The Warranty" }; var newWarranty = ne

我使用的是Entity Framework 6.1.3,在这种情况下,我检索具有导航属性的实体(使用Include())并将其与上下文断开连接,更改外键Id,然后将其重新附加到新的DbContext:

// Init the Db
using (var db = new MyContext())
{
   var theWarranty = new ProductWarranty { WarrantyName = "The Warranty" };
   var newWarranty = new ProductWarranty { WarrantyName = "New Warranty" };
   var brand = new ProductBrand { BrandName = "The Brand", DefaultWarranty = theWarranty };

   db.ProductBrands.Add(brand);
   db.ProductWarranties.Add(newWarranty);

   db.SaveChanges();
}

// Load the detached Brand
ProductBrand detachedBrand;
using (var db = new MyContext())
{
   detachedBrand = db.ProductBrands.AsNoTracking()
      .Include(b => b.DefaultWarranty)  // <<< If this line is removed the Attach works
      .First(x => x.Id == 1);
}

// Modify the Default Warranty Foreign Key
detachedBrand.DefaultWarranty = null;
detachedBrand.DefaultWarranty_Id = 2;

// Attempt to re-attach and save the changes
using (var db = new MyContext())
{
   var entity = db.Set<ProductBrand>().Attach(detachedBrand); // <<< This line throws the exception

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

   db.SaveChanges();
}
//初始化数据库
使用(var db=new MyContext())
{
var theWarranty=新产品保修{WarrantyName=“保修”};
var newWarranty=新产品保修{WarrantyName=“新保修”};
var品牌=新产品品牌{BrandName=“品牌”,默认保修=保修};
db.ProductBrands.Add(品牌);
db.ProductGuarants.Add(新担保);
db.SaveChanges();
}
//加载分离的品牌
产品品牌分离品牌;
使用(var db=new MyContext())
{
detachedBrand=db.ProductBrands.AsNoTracking()
.Include(b=>b.DefaultWarranty)//t.Id);
//性质
this.Property(t=>t.BrandName)
.IsRequired()
.HasMaxLength(40);
//表和列映射
本表为ToTable(“产品品牌”);
this.Property(t=>t.Id).HasColumnName(“Id”);
this.Property(t=>t.BrandName).HasColumnName(“BrandName”);
this.Property(t=>t.DefaultWarranty\u Id).HasColumnName(“DefaultWarranty\u Id”);
//关系
this.has可选(t=>t.default保修)
.有很多(t=>t.ProductBrands)
.HasForeignKey(d=>d.DefaultWarranty\u Id)
.WillCascadeOnDelete(假);
}
}
产品保修
公共部分类产品保修
{
公共产品保修()
{
this.ProductBrands=新列表();
}
公共int Id{get;set;}
公共字符串担保名称{get;set;}
公共虚拟ICollection产品品牌{get;set;}
}
产品保修图
公共类产品保修映射:EntityTypeConfiguration
{
公共产品保证映射()
{
//主键
this.HasKey(t=>t.Id);
//性质
this.Property(t=>t.WarrantyName)
.IsRequired()
.HasMaxLength(40);
//表和列映射
本表为ToTable(“产品保证”);
this.Property(t=>t.Id).HasColumnName(“Id”);
this.Property(t=>t.warkuryName).HasColumnName(“warkuryName”);
}
}

启用
ProxyCreationEnabled
时,即使实体未被任何上下文跟踪,它们也会以某种方式在内部相互连接。我的意思是,动态代理实体会仔细记录FK中的任何更改,以强制执行引用完整性。因此,只需关闭
ProxyCreationEnabled

public MyContext()
{
     this.Configuration.ProxyCreationEnabled = false;
}

但如果你问我的意见,我更喜欢在跟踪实体时更改实体,修改后将其分离。

我在尝试分配新的外键值时遇到了同样的问题

在更新了核心对象上的外键之后,我正在执行附加操作。这是一个问题

相反,我现在附加到对象,然后将更改应用到字段

public static bool ChangeForeignKeyAssocation(baseobject existing, int newFK, bool throwOnError = true) {
  try {
    using (var e = new Entities()) {
      e.table.Attach(existing);
      e.Entry(existing).State = EntityState.Modified;

      existing.related_table_id = newFK;

      int result = sbe.SaveChanges();
      return (result == 1);
    }
  } catch (Exception ex) {
    //LogIt.E(ex);
    if (throwOnError) {
      throw ex;
    } else {
      return false;
    }
  }
}

我测试了它,它毫无例外地工作@Alireza-我的开发和项目的细节是VS2013、.net 4.5.2。我再次运行代码,仍然得到错误。我还将我的项目发送给了一位同事,他也经历了同样的行为……并且和我一样困惑。你有运行代码的具体步骤吗?你会将你的项目发送给我吗?@Alireza不确定你是如何测试它的,但我可以很容易地复制它,只需一个简单的模型就足够了。看起来分离的实体仍然对关系有一些了解(由
Include
加载),这对我来说相当奇怪。@Alireza-从Fantastic下载项目文件!加载实体时设置ProxyCreationEnabled=false就成功了!至于“我更喜欢在跟踪实体时更改实体,修改后将其分离”——示例是WPF应用程序的简化版本,用户/UI层修改分离的实体,然后将其发送回应用程序层。
public partial class ProductWarranty
{
    public ProductWarranty()
    {
        this.ProductBrands = new List<ProductBrand>();
    }

    public int Id { get; set; }
    public string WarrantyName { get; set; }
    public virtual ICollection<ProductBrand> ProductBrands { get; set; }
}
public class ProductWarrantyMap : EntityTypeConfiguration<ProductWarranty>
{
    public ProductWarrantyMap()
    {
        // Primary Key
        this.HasKey(t => t.Id);

        // Properties
        this.Property(t => t.WarrantyName)
            .IsRequired()
            .HasMaxLength(40);

        // Table & Column Mappings
        this.ToTable("ProductWarranties");
        this.Property(t => t.Id).HasColumnName("Id");
        this.Property(t => t.WarrantyName).HasColumnName("WarrantyName");
    }
}
public MyContext()
{
     this.Configuration.ProxyCreationEnabled = false;
}
public static bool ChangeForeignKeyAssocation(baseobject existing, int newFK, bool throwOnError = true) {
  try {
    using (var e = new Entities()) {
      e.table.Attach(existing);
      e.Entry(existing).State = EntityState.Modified;

      existing.related_table_id = newFK;

      int result = sbe.SaveChanges();
      return (result == 1);
    }
  } catch (Exception ex) {
    //LogIt.E(ex);
    if (throwOnError) {
      throw ex;
    } else {
      return false;
    }
  }
}