C# 财产';Id';是对象的一部分';s键信息,无法修改

C# 财产';Id';是对象的一部分';s键信息,无法修改,c#,foreign-keys,entity-framework-4,C#,Foreign Keys,Entity Framework 4,我正在使用EntityFramework4.0,但有一个我无法解决的愚蠢问题 我有两张桌子: 联系人:Id(主键)、值、ContactTypeId(ContactType的外键) 联系人类型:Id(主键)、类型(家庭、手机、工作等) 实体框架创建了以下两个实体: 联系人:Id、值、联系人类型(导航属性) ContactType:Id、类型、联系人(导航属性) 我正在使用以下代码获取联系人并更新该特定联系人的联系人类型: Contact contact = dbContext.Contacts.S

我正在使用EntityFramework4.0,但有一个我无法解决的愚蠢问题

我有两张桌子:

  • 联系人:Id(主键)、值、ContactTypeId(ContactType的外键)
  • 联系人类型:Id(主键)、类型(家庭、手机、工作等)
  • 实体框架创建了以下两个实体:

  • 联系人:Id、值、联系人类型(导航属性)
  • ContactType:Id、类型、联系人(导航属性)
  • 我正在使用以下代码获取联系人并更新该特定联系人的联系人类型:

    Contact contact = dbContext.Contacts.Single(c => c.Id == 12345);
    contact.ContactType.Id = 3;
    
    引发以下异常:

    The property 'Id' is part of the object's key information and cannot be modified.
    
    看起来很简单!我不明白

    试试看

    contact.ContactType = differentContactType;
    


    您正在尝试将ContactType(联系人)的Id设置为3。

    框架创建的实体没有Contact.ContactTypeId属性。它会自动将其删除,并在联系人实体内创建ContactType关联

    正如您所建议的,使其工作的方法是通过查询数据库并将其分配给contact.ContactType来创建ContactType对象。例如:

    Contact contact = dbContext.Contacts.Single(c => c.Id == 12345);
    ContactType contactType = dbContext.ContactType.Single(c => c.Id == 3);
    contact.ContactType = contactType;
    

    有两种类型的关联。独立关联,其中相关键仅作为导航属性显示。第二种是外键关联,可以使用外键和导航属性更改相关的键。因此,您可以执行以下操作

    //选项1通用选项

    var contacttype = new ContactType{Id = 3};
    db.ContactTypes.Attach(contacttype);
    customer.ContactType = contacttype;
    
    选项2外键选项

    contact.ContactTypeId = 3;
    
    //通用选项适用于外键和独立关联

    contact.ContactReference.EntityKey = new EntityKey("container.contactset","contacttypeid",3);
    

    我正在使用EF4.0和WPF,我遇到了类似的问题,并且。。。。 用一种非常简单的方式找到了解决问题的方法(至少对我来说)

    因为,和您一样,我认为更新表中的字段(例如,在您的案例中:Contact)必须很简单,该字段由另一个表(例如,在您的案例中:ContactType)中的foreignkey引用

    但是,错误消息: “…是对象密钥信息的一部分,无法修改。” 仅在您尝试更新主键时出现(这根本不是我的意图)

    仔细查看了我的EntityModel的XML代码,发现它:

    
    ...
    ...
    
    出于某种原因(可能是我在数据库中犯了一些愚蠢的错误),当Visual Studio从我的数据库中为我自动生成数据模型时,它在表(Contact)中添加了内容,我想在该表中更新字段(
    ContactTypeID
    )一个
    属性ref
    第二行

    我刚刚删除了第二个
    属性ref

    
    
    在这两种模型中,存储模型概念模型以及。。。。问题已解决:-)

    因此,仍然是这样的:

    
    ...
    ...
    
    更新和插入现在像婴儿一样平稳运行…:-)


    因此,最好检查数据模型的XML,以验证只有您的PK列为
    PropertyRef
    。为我工作…:-)

    发生此问题是因为您多次引用同一对象。这不是EF的限制,而是一种安全功能,可确保您不会插入具有两个不同ID的同一对象。因此,要实现您想要做的事情,只需创建一个新对象并将新创建的对象添加到数据库中

    **这个问题经常发生在循环内部。如果使用while或foreach循环,请确保新创建的对象位于循环体中

    试试这个:

    Contact contact = dbContext.Contacts.Single(c => c.contactTypeId == 1234);
    contact.contactTypeId = 4;
    dbContext.AddObject(contact);
    dbContext.SaveChanges();
    

    我在同时从两个不同的上下文编辑相关对象时发生了这种情况。例如:

    DataContext ctxA = new DataContext();
    DataContext ctxB = new DataContext();
    
    Author orwell = new Author {Name = "George Orwell" };
    ctxA.Add(orwell);
    ctxB.Add(new Book {Name = "1984", Author = orwell});
    
    ctxA.SaveChanges();
    ctxB.SaveChanges();
    

    我的案例有点复杂(因为这显然是很愚蠢的),但本质上这是导致我案例中错误的原因。

    在我的案例中,我想复制对象,但更改id,所以我使用这个

    Common.DataContext.Detach(object);
    

    像符咒一样工作

    另一个奇怪的行为在我的例子中,我有一个没有任何主键的表。EF本身使用所有列创建复合主键,即:

     <Key>
            <PropertyRef Name="ID" />
            <PropertyRef Name="No" />
           <PropertyRef Name="Code" />
       </Key>
    
    
    
    无论何时执行任何更新操作,它都会引发以下异常:

    The property 'Id' is part of the object's key information and cannot be modified.
    
    属性“Code”是对象关键信息的一部分,不能 可以修改

    解决方案:从EF图中删除表,然后转到数据库,在产生问题的表上添加主键,然后将表重新添加到EF图中。现在一切就绪,它将有一个键,即

    <Key>
            <PropertyRef Name="ID" />
    </Key>
    

    我希望这能帮助其他人,因为我知道我没有更新PK,我肯定有一个PK。我将PK值数据绑定到菜单栏,以显示当前PK值,这就是问题的原因。

    首先删除 下一个添加

    简单地说

    public static IEnumerable UserIntakeFoodEdit(FoodIntaked data)
            {
                DBContext db = new DBContext();
                var q = db.User_Food_UserIntakeFood.AsQueryable();
                var item = q.Where(f => f.PersonID == data.PersonID)
                      .Where(f => f.DateOfIntake == data.DateOfIntake)
                      .Where(f => f.MealTimeID == data.MealTimeIDOld)
                      .Where(f => f.NDB_No == data.NDB_No).FirstOrDefault();
    
                item.Amount = (decimal)data.Amount;
                item.WeightSeq = data.WeightSeq.ToString();
                item.TotalAmount = (decimal)data.TotalAmount;
    
    
                db.User_Food_UserIntakeFood.Remove(item);
                db.SaveChanges();
    
                item.MealTimeID = data.MealTimeID;//is key
    
                db.User_Food_UserIntakeFood.Add(item);
                db.SaveChanges();
    
                return "Edit";
            }
    

    在我的例子中,我只是将主键设置为丢失的表,重新执行了mappind edmx,它确实工作了 当你有主键时,你只有这个

    <PropertyRef Name="id" />
    
    
    
    但是,如果未设置主键,则

    <PropertyRef Name="id" />
    <PropertyRef Name="col1" />
    <PropertyRef Name="col2" />
    
    
    

    请注意,Juergen Fink answer是一个解决方案

    在我的例子中,我创建了一个一起声明和初始化的对象。我只是在构造函数中进行了初始化,或者您可以在需要时初始化对象。

    在我的例子中,当我删除ID字段的KEY属性时,出现了错误

    // [Key]
    public long Id { get; set; }
    
    因此,只要将属性放回原来的位置,就可以让一切恢复正常

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }
    
    你应该加上

     db.Entry(contact).State = EntityState.Detached;
    

    在.SaveChanges()之后

    对我来说,问题是由于我的表缺少主键造成的,在为表设置PK后,问题就消失了

    对不起,我是在执行linq sql而不是EF。在我的情况下,只要在循环中移动对象并相应地增加ID,问题就解决了。非常感谢<代码>新联系人()是一个冗余的初始值设定项!可能是我一直在寻找的