Entity Framework 将对象添加到集合导致意外行为

Entity Framework adding object to collection results in unexpected behaviour

我目前正在使用 Entity Framwork 6 开发一个新的 ASP.NET MVC 应用程序。 我有 2 个 类 一起工作:Account 和 AccountAddition。 Account 表示基本用户帐户,AccountAddition 包含例如联系人、通知或上次登录时间的 ICollections。

现在我只是想通过 curAcc.Addition.Contacts.Add(correspondingAccount) 向 AccountAdditions ICollection Contacts 属性 添加一个新帐户,其中 correspondingAccount 是要添加的帐户对象(两个帐户都在数据库中给出).

问题是当我将 correspondingAccount 添加到当前帐户的联系人时,引用 correspondingAccount.Addition 突然指向当前帐户的 AccountAddition

问题部分:

...
Account curAcc = context.Accounts.FirstOrDefault(p => p.Alias == currentAlias);
        if(ModelState.IsValid)
        {
            var correspondingAccount = context.Accounts.FirstOrDefault(p => p.Alias == addAlias);
            if(correspondingAccount != null)
            {
                curAcc.Addition.Contacts.Add(correspondingAccount);
                context.SaveChanges();
                ...

代码先行类:

public class Account
{
    public Account()
    {
        IsEnabled = true;
    }
    [Key]
    public int ID { get; set; }
    public string Alias { get; set; }
    [DataType(DataType.Password)]
    public string Password { get; set; }
    public byte[] Salt { get; set; }

    [ForeignKey("Config")]
    public int ConfigID { get; set; }
    public virtual CryptoConfig Config { get; set; }
    [ForeignKey("Addition")]
    public int AdditionID { get; set; }
    public virtual AccountAddition Addition { get; set; }
    public virtual ICollection<AccountRoleLink> Roles { get; set; }
    public bool IsEnabled { get; set; }
}

public class AccountAddition
{
    public AccountAddition()
    {
        CreatedOn = DateTime.Now;
        Contacts = new List<Account>();
        Notifications = new List<Notification>();
    }
    [Key]
    public int ID { get; set; }
    public virtual ICollection<Account> Contacts { get; set; }
    public virtual ICollection<Notification> Notifications { get; set; }
    public string ContactEmail { get; set; }

    public Nullable<DateTime> LastLogin { get; set; }
    public Nullable<DateTime> LastFailedLogin { get; set; }
    public Nullable<DateTime> CreatedOn { get; set; }
}

更多示例:

Account curAcc = // Find current account (current context)
Account correspondingAcc = // Get account to add (same context)

curAcc.Addition is Addition with id 1
correspondingAcc.Addition is Addition with id 2
// correspondingAcc gets added via curAcc.Addition.Contacts.add(cor...)
// context saves changes
curAcc.Addition is Addition with id 2 afterwards
correspondingAcc.Addition is Addition with id 2 afterwards

我尝试在 EF 教程中进行谷歌搜索和搜索,但没有找到解决方案。 怎么了?

感谢您的宝贵时间

更新:

好吧,显然 Ody 提供的解决方案没有按预期工作。 我尝试从 Notification 和 Contact 集合中删除 virtual 关键字。 剪下的现在看起来像这样:

Account curAcc = GetCurrentAccount();
        if(ModelState.IsValid)
        {
            var correspondingAccount = context.Accounts.FirstOrDefault(p => p.Alias == addAlias);
            if(correspondingAccount != null)
            {
                curAcc.Addition.Contacts.Add(correspondingAccount);

                var existingCorrespondingAccount = curAcc.Addition
                                         .Contacts.Where(a => a.Alias == addAlias)
                                         .FirstOrDefault();
                if (existingCorrespondingAccount != null)
                {
                    context.Accounts.Add(curAcc);
                }


                context.SaveChanges();

在调用 Add 方法后,context.Accounts 中的帐户对象指向错误的 AccountAddition。当我想将账户f2(AdditionId 2)添加到账户f1(AdditionId 1)时,f2的additionId指向1.

当我调用 SaveChanges 时,抛出 System.Data.Entity.Infrastructure.DbUpdateException。

{"An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details."}

内部异常是

{"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions."}

我遵循了link并尝试使用OptimisticConcurrencyException和DbUpdateConcurrencyException来捕获它,但是ex是DbUpdateException,它们没有被它们捕获。

这令人沮丧:(

问题是,每当您将实体添加到相关 属性 集合并调用 SaveChanges() 时,它不会检查该 ID 是否已存在。无论如何它都会创建一个新的。这就是 EF 的工作原理。

要解决您的问题,您应该在使用 ID 手动添加之前检查该帐户是否已存在于 acc.Contacts 中。

像这样

Account curAcc = context.Accounts.FirstOrDefault(p => p.Alias == currentAlias);
var correspondingAccount = context.Accounts.FirstOrDefault(p => p.Alias == addAlias);
if (correspondingAccount != null)
{
    curAcc.Addition.Contacts.Add(correspondingAccount);

    var existingCorrespondingAccount = curAcc.Addition
                                             .Contacts.Where(a => a.Alias == addAlias)
                                             .FirstOrDefault();
    if(existingCorrespondingAccount != null)
    {
          context.Accounts.Add(new Account
          {
               AdditionID = curAcc.AdditionID,
               Alias = curAcc.Alias,
               ConfigID = curAcc.ConfigID,
               IsEnabled = curAcc.IsEnabled,
               Password = curAcc.Password,
               Salt = curAcc.Salt
           });
    }
    context.SaveChanges();
}