C# EF 6代码首先,使用“包含在导航上”属性更改外键Id会导致;发生引用完整性约束冲突";错误
我使用的是Entity Framework 6.1.3,在这种情况下,我检索具有导航属性的实体(使用Include())并将其与上下文断开连接,更改外键Id,然后将其重新附加到新的DbContext: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
// 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;
}
}
}