[英]Saving single EntityObject with Entity Framework code first
我在一个项目中使用Entity Framework 6.0.0,首先使用代码和DbContext API。 在我的应用中,有2个具有一对多关系的实体对象,如下所示
class RefTable {
[Key]
public int Id { get; set; }
public string RefName { get; set; }
public virtual ICollection<Data> DataDetails { get; set; }
}
public class Data
{
[Key]
public int Id { get; set; }
public string RefId { get; set; }
[ForeignKey("RefId")]
public virtual RefTable Machine { get; set; }
}
RefTable
将在应用程序启动时填充,并且几乎不会进行任何更改。 但是, Data
将不时发生变化。
我的Context.cs如下
public class MyDbContext : DbContext
{
public MyDbContext()
: base("name=CounterDbString")
{
Database.SetInitializer<MyDbContext>(new CreateDatabaseIfNotExists<MyDbContext>());
}
public DbSet<RefTable> RefData { get; set; }
public DbSet<Data> Data { get; set; }
}
我用来保存数据的代码
public void Write(IList<RefTable> refDataList)
{
foreach (var entity in refDataList)
{
var element = myContext.RefData.Find(entity.Id);
if (element == null)
{
myContext.RefData.Add(entity);
}
}
myContext.SaveChanges();
}
public void Write(IList<Data> dataList)
{
myContext.Data.AddRange(dataList);
myContext.SaveChanges();
}
当我尝试在第二个函数中执行myContext.SaveChanges()
时,总是会收到更新错误,指出violation of Primary Key
因为它试图将相同的数据插入RefTable
。 有没有一种方法可以只保存Data
对象中的更改?
当您从DbContext获取实体时,它被认为是附加到上下文的,因此上下文知道您对实体所做的任何更改。 因此,在修改实体后,您不应将其再次添加到DbContext或对其进行特殊处理。 但是,如果实体丢失了它与DbContext的连接或是一个新的连接,则应将其添加到上下文中。
我仍然看不到完整的代码,但是我认为问题会发生,因为在某些时候某个实体变得未连接,然后被修改,并且当SaveChanges发生时被认为是新实体,从而导致FK错误。
这是一个基本工作原理的小例子:
private static void Main(string[] args) {
var db = new MyDbContext();
var reftable1 = new RefTable() {Id = 100, RefName = "ref1"};
var listData1 = new List<Data>();
for (int i=0; i<5; i++)
listData1.Add(new Data() {Id = i, Machine = reftable1, RefId = reftable1.Id});
reftable1.DataDetails = listData1;
db.RefData.Add(reftable1);
var reftable2 = new RefTable() {Id = 200, RefName = "ref2"};
var listData2 = new List<Data>();
for (int i=5; i<10; i++)
listData2.Add(new Data() {Id = i, Machine = reftable2, RefId = reftable2.Id});
reftable2.DataDetails = listData2;
db.RefData.Add(reftable2);
db.SaveChanges();
db = new MyDbContext(); //lose connection to existing dbContext
//now reftable1 is unattached, so if not lookup it from new dbContext it will be recreated!!!
reftable1 = db.RefData.Single(x => x.RefName == "ref1"); //comment to see the difference
//perform some update
var data = db.Data.Where(x => x.Id > 7).ToList();
foreach (var d in data) {
d.Machine = reftable1;
}
db.SaveChanges();
Console.ReadLine();
}
而您的班级做了些微改动:
public class RefTable {
[Key]
public int Id { get; set; }
public string RefName { get; set; }
public virtual ICollection<Data> DataDetails { get; set; }
}
public class Data {
[Key]
public int Id { get; set; }
public int RefId { get; set; }
[ForeignKey("RefId")]
public virtual RefTable Machine { get; set; }
}
public class MyDbContext : DbContext {
public MyDbContext()
: base("name=CounterDbString") {
Database.SetInitializer(new CreateDatabaseIfNotExists<MyDbContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<RefTable>().HasMany(x => x.DataDetails).WithRequired(x => x.Machine);
base.OnModelCreating(modelBuilder);
}
public DbSet<RefTable> RefData { get; set; }
public DbSet<Data> Data { get; set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.