我在我的应用程序中使用代码优先实体框架(代码优先)。
当我尝试添加一个NEW对象并将其保存到数据库时,EF会抛出此错误。
属性' AccountNumber'是对象关键信息的一部分 并且无法修改。
首先令这个错误混淆的是AccountNumber不是该表中的主键。
在阅读了几篇帖子来解决这个问题后,我尝试在它保存之前创建一个全新的对象:
public void CreateCustomerLookUp(CustomerLookUp customerLookUp)
{
//To avoid EF specific error recreating object using NEW - wierd!
//http://stackoverflow.com/questions/3187963/the-property-id-is-part-of-the-objects-key-information-and-cannot-be-modified
customerLookUp.LastUpdated = DateTime.Now;
var encryptedCustomerLookUp = EncryptCustomerLookUp(customerLookUp);
var newCustomerLookup = new CustomerLookUp()
{
AccountNumber = encryptedCustomerLookUp.AccountNumber,
EmailAddress = encryptedCustomerLookUp.EmailAddress,
MobileNumber = encryptedCustomerLookUp.MobileNumber,
UmbracoMemberId = encryptedCustomerLookUp.UmbracoMemberId,
UpdateCode = encryptedCustomerLookUp.UpdateCode,
UpdateNotification = encryptedCustomerLookUp.UpdateNotification
};
customerDataContext.Entry(newCustomerLookup).State = EntityState.Added;//<< Throwing error here!
customerDataContext.SaveChanges();
}
我也试过
customerDataContext.CustomerLookUps.Add(newCustomerLookup);
而不是
customerDataContext.Entry(newCustomerLookup).State = EntityState.Added;
但我仍然得到错误。这就是我的CustomerLookup实体的样子,我无法弄清楚为什么EF认为AccountNumber不是Key。 (我在想,也许主键和键是两个不同的东西?)
public class CustomerLookUp
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[StringLength(256)]
public string AccountNumber { get; set; }
[StringLength(256)]
public string MobileNumber { get; set; }
[StringLength(256)]
public string EmailAddress { get; set; }
[StringLength(256)]
public string UpdateCode { get; set; }
[StringLength(256)]
public string UmbracoMemberId { get; set; }
public bool UpdateNotification { get; set; }
public DateTime LastUpdated { get; internal set; }
}
这是我的上下文类,只有2个DB-sets 没有链接。 我查看了数据库以查看生成的内容及其预期的两个表。另一个实体&#34;客户&#34;确实有AccountNumber作为PK,但我不是想保存到那个表。
public partial class CustomerContext : DbContext
{
public CustomerContext()
: base("name=CustomerContext")
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<CustomerLookUp> CustomerLookUps { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
为了完整性,这是Customer类。 (这个有 AccountNumber作为PK,但这是一个完全不同的表,而不是我想要保存的表。
public class Customer
{
[Key]
[Required]
[StringLength(256)]
public string AccountNumber { get; set; }
[Required]
[StringLength(256)]
public string SupplyPostCode { get; set; }
[StringLength(256)]
public string Title { get; set; }
[StringLength(256)]
public string Forenames { get; set; }
[StringLength(256)]
public string Name { get; set; }
}
更新:我已取得进展,但尚未完全解决问题。我决定做的是重命名列,所以我在CustomerLookUp类的AccountNumber的每个表中有两个不同的名称我将名称更改为AccountNumberX然后再次运行修复。我仍然有同样的错误。这意味着问题肯定与我试图保存的实体无关。 EF抱怨客户等级。
在最终调用CreateCustomerLookUp方法的业务逻辑中,我正在检索客户记录并对其进行解密,我需要这样做才能读取纯文本值,但我不是要求EF保存这些更改。
所以当我保存newCustomerLookup对象时,它还在尝试保存我之前检索到的客户记录的Decrypted版本。
所以真正的问题是,我如何告诉EF我不希望它保存对该对象所做的更改?我只想保存新的newCustomerLookup对象。
答案 0 :(得分:1)
根据您的更新,您需要查看DbContext
的生命周期。默认情况下,DbContext
会跟踪其所知的任何实体中的更改,然后在您致电SaveChanges()
时尝试保存这些更改。
在这种情况下看起来似乎正在发生的事情是你在某个地方定义DbContext
,与Customer
合作,然后与CustomerLookup
合作,同时{ {1}}处于活动状态并且知道您的实体(例如,它将知道您从数据库中检索的任何实体)。然后,当您致电DbContext
时,它会尝试保存已知的所有内容。
您通常只想在需要时创建和处置SaveChanges()
。他们是轻量级的,您通常希望他们能够持续工作单元(无论您的应用程序中是什么)。养成在DbContexts
块中使用它们以保持清洁的习惯。所以你的方法可能类似于:
using
注意:
您还需要在代码中的其他位置进行类似的更改
本地化public void CreateCustomerLookUp(CustomerLookUp customerLookUp)
{
using (var context = new CustomerContext())
{
customerLookUp.LastUpdated = DateTime.Now;
var encryptedCustomerLookUp = EncryptCustomerLookUp(customerLookUp);
var newCustomerLookup = new CustomerLookUp()
{
AccountNumber = encryptedCustomerLookUp.AccountNumber,
EmailAddress = encryptedCustomerLookUp.EmailAddress,
MobileNumber = encryptedCustomerLookUp.MobileNumber,
UmbracoMemberId = encryptedCustomerLookUp.UmbracoMemberId,
UpdateCode = encryptedCustomerLookUp.UpdateCode,
UpdateNotification = encryptedCustomerLookUp.UpdateNotification
};
context.Entry(customerLookUp).State = EntityState.Modified;
context.CustomerLookUps.Add(newCustomerLookup);
context.SaveChanges();
}
}
。单独进行上述更改将导致
2 DbContexts
处于活跃状态,因此您可能仍会遇到其他问题
跟踪问题。
您可能会进一步限制范围
一点点重构的方法。我把整个方法都包括在内了
我看到你正在更新2个实体(DbContexts
和
customerLookup
)而且我不知道你在做什么
newCustomerLookup
。
答案 1 :(得分:0)
正如“Tone&#39;发生此错误是因为EF正在尝试更新已更改的所有已知实体,即使您未明确调用:
customerDataContext.Entry(newCustomerLookup).State = EntityState.Added;
customerDataContext.SaveChanges();
在我的情况下,存储在数据库中的数据是加密的。在我的业务逻辑中,我需要取消加密客户,执行一些业务逻辑,然后更新customerLookUp记录。通过取消加密客户记录,我已经有效地更改了它,这是我尝试保存customerLookup记录时导致错误的原因。
<强>解决方案:强>
有几种不同的方法可以解决这个问题。一种方法是创建第二个数据上下文对象。您将使用第一个获取记录并取消加密,然后第二个将用于将实体保存到数据库。虽然这有效,但我发现它有点混乱。
我没有取消加密来自dbcontext的记录,而是将数据原样复制到新对象中。然后我取消加密那个新对象,这样我永远不会更改记录,所以当我调用saveChanges()时,EF所做的唯一更改是我明确更改的记录。
这个概念被称为&#34;数据传输对象模式&#34;你可以在这里阅读更多相关信息:
https://www.exceptionnotfound.net/entity-framework-and-wcf-mapping-entities-to-dtos-with-automapper/