简体   繁体   English

EF一对一更新失败

[英]EF One-to-One Update fails

I have one-to-one relationship defined in EF6 which works for Inserts. 我在EF6中定义了一对一关系,适用于插入。 Unfortunately when I try an update with a disconnected record, I receive an error. 不幸的是,当我尝试使用断开记录的更新时,收到错误消息。 Here are details: 详情如下:

.NET Source: .NET来源:

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. “ Customer_Account” AssociationSet中的关系处于“已添加”状态。 Given multiplicity constraints, a corresponding 'Customer_Account_Target' must also in the 'Added' state. 给定多重性约束,相应的“ Customer_Account_Target”也必须处于“已添加”状态。

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. 使用EF 6.2和.NET 4.7.1。

This is because you are adding the entity again. 这是因为您要再次添加实体。 You need to attach the object first by calling db.Accounts.Attach(account); 您需要先通过调用db.Accounts.Attach(account);来附加对象db.Accounts.Attach(account); .

Or a better approach would be to first fetch based on Id and then modify the desired fields like this : 或更好的方法是先基于Id取回,然后像这样修改所需的字段:

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

This is a side effect of the db.Accounts.Add(account); 这是db.Accounts.Add(account);db.Accounts.Add(account); call. 呼叫。 It sets some shadow state to Added which cannot be negated by the next State manipulations. 它将某些阴影状态设置为“已Added ,而下一个“ State操作无法对其进行否定。

Attach in advance doesn't work in this case. 在这种情况下,预先Attach无效。 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 . 因此,可以使用@Harsh的第二条建议,或者如果要进行强制更新,请不要调用Add而只需将accountState设置为Modified This will attach it and mark it as modified w/o affecting the associated Customer . 这将附加它并将其标记为已修改,而不会影响关联的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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM