EF One-to-One Update fails

给你一囗甜甜゛ 提交于 2020-01-24 16:15:14

问题


I have one-to-one relationship defined in EF6 which works for Inserts. Unfortunately when I try an update with a disconnected record, I receive an error. Here are details:

.NET Source:

namespace EF_ConsoleApp_Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            int? accountId;
            int? customerId;

            using (var db = new MainContext())
            {
                var account = new Account
                {
                    AccountNumber = "1234",
                    Customer = new Customer {FirstName = "John"}
                };

                db.Accounts.Add(account);
                db.SaveChanges();

                accountId = account.Id;
                customerId = account.Customer.Id;
            }

            using (var db = new MainContext())
            {
                // disconnected record
                var account = new Account()
                {
                    Id = accountId,
                    AccountNumber = "9876",
                    Customer = new Customer() {Id = customerId}
                };

                db.Accounts.Add(account);
                db.Entry(account).State = EntityState.Modified;
                db.Entry(account.Customer).State = EntityState.Unchanged;

                db.SaveChanges(); // Error occurs here
            }
        }

        [Serializable]
        [Table("CUSTOMERS")]
        public class Customer
        {
            [Key] [Column("CUSTOMER_ID")] public int? Id { get; set; }

            [Required]
            [Column("FIRST_NAME")]
            [StringLength(45)]
            public string FirstName { get; set; }

            public virtual Account Account { get; set; }

            public Customer() { }
        }

        [Serializable]
        [Table("ACCOUNTS")]
        public class Account
        {
            [Key]
            [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
            [Column("ACCOUNT_ID")]
            public int? Id { get; set; }

            [Required]
            [Column("ACCOUNT_NUMBER")]
            [Display(Name = "Account Number")]
            [StringLength(16)]
            public string AccountNumber { get; set; }

            public virtual Customer Customer { get; set; }

            /// <summary>
            /// Default Constructor
            /// </summary>
            public Account() { }
        }

        internal class MainContext : DbContext
        {
            internal MainContext() : base("name=ACHRE.Context")
            {
                Database.SetInitializer<MainContext>(null);
            }

            public virtual DbSet<Account> Accounts { get; set; }

            public virtual DbSet<Customer> Customers { get; set; }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                // Configure FK
                modelBuilder.Entity<Customer>()
                    .HasRequired(c => c.Account)
                    .WithRequiredPrincipal(a => a.Customer)
                    .Map(m => m.MapKey("CUSTOMER_ID"));

                base.OnModelCreating(modelBuilder);
            }
        }
    }
}

Database Table Create statements:

CREATE TABLE [dbo].[CUSTOMERS](
    [CUSTOMER_ID] [INT] IDENTITY(1,1) NOT NULL,
    [FIRST_NAME] [varchar](45) NOT NULL,
 CONSTRAINT [PK_CUSTOMERS] PRIMARY KEY CLUSTERED 
(
    [CUSTOMER_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[ACCOUNTS](
    [ACCOUNT_ID] [INT] IDENTITY(1,1) NOT NULL,
    [CUSTOMER_ID] [int] NOT NULL,
    [ACCOUNT_NUMBER] [varchar](16) NOT NULL,
 CONSTRAINT [PK_ACCOUNTS] PRIMARY KEY CLUSTERED 
(
    [ACCOUNT_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

ALTER TABLE [dbo].[ACCOUNTS]  WITH CHECK ADD  CONSTRAINT [FK_ACCOUNTS_CUSTOMERS] FOREIGN KEY([CUSTOMER_ID])
REFERENCES [dbo].[CUSTOMERS] ([CUSTOMER_ID])
GO

Error:

A relationship from the 'Customer_Account' AssociationSet is in the 'Added' state. Given multiplicity constraints, a corresponding 'Customer_Account_Target' must also in the 'Added' state.

What do I need to update to make this work?

Notes

  • This related to question I asked before that was related to Inserts. The Insert was resolved but introduced this issue when the Foreign Keys were removed.
  • Using EF 6.2 and .NET 4.7.1.

回答1:


This is because you are adding the entity again. You need to attach the object first by calling db.Accounts.Attach(account);.

Or a better approach would be to first fetch based on Id and then modify the desired fields like this :

       using (var db = new MainContext())
        {
            var account =  db.Accounts.SingleOrDefault(x => x.id == accountId);
            account.AccountNumber = "9876"
            db.SaveChanges();
        }



回答2:


This is a side effect of the db.Accounts.Add(account); call. It sets some shadow state to Added which cannot be negated by the next State manipulations.

Attach in advance doesn't work in this case. So either use the second suggestion by @Harsh, or if you want to do forced update, don't call Add but simply set the State of the account to Modified. This will attach it and mark it as modified w/o affecting the associated Customer.

using (var db = new MainContext())
{
    // disconnected record
    var account = new Account()
    {
        Id = accountId,
        AccountNumber = "9876",
        Customer = new Customer() {Id = customerId}
    };

    db.Entry(account).State = EntityState.Modified; // <-- enough

    db.SaveChanges();
}


来源:https://stackoverflow.com/questions/50141979/ef-one-to-one-update-fails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!