none
Entity Framework Many to Many Disconnected Mode Update - HowTo RRS feed

  • Question

  • I am using EF 6 Code First, and I have the following database tables:

    Account

    Contract

    AccountContract

    AccountContract is a junction table that has two primary foreign keys that point to an Account object ID and a Contract object ID. Nothing too fancy there. I am then reading in some data and attempting to update the Account object's ICollection of Contracts. This is where things become unclear for me, following is the code that fails and the code I've found to work, and I wish to know if this is the correct way of doing things, or is there a better way. Thanks in advance for your thoughts/comments.

    // Example #1 in Connected State: Successfully updates the junction table, but I get a duplicate contract created.
    using (var db = new ClientDbContext())
    {
    	var account = db.accounts
    		.Where(w => w.account_id == 41) // Test Account
    		.FirstOrDefault();
    
    	if (account != null && !account.contracts.Any(a => a.contract_id == 5)) // Test Contract.
    	{
    		contracts newContract = new contracts();
    
    		newContract.contract_id = 5;
    		newContract.contract_name = "Name";
    		newContract.contract_description = "Some Text";
    		
    		account.contracts.Add(newContract);
    
    		db.Entry(account).State = System.Data.Entity.EntityState.Modified;
    		db.SaveChanges();
    	}
    }
    
    // AccountController Update Function.
    public void Update(account item)
    {
    	using (var db = new ClientDbContext())
    	{
    		try
    		{
    			db.accounts.Create(item); // Probably duplicate is created as we are creating a new Account item. All makes sense.
    			db.SaveChanges();
    		}
    		catch (Exception e)
    		{
    			throw e;
    		}
    	}
    }
    
    // Example #2 in Disconnected State: Doesn't work, no changes in the database.
    int accountID = 41;
    int contractID = 5;
    var controller = new AccountController();
    
    var account = controller.GetByID(accountID); // Get the test Account.
    
    if (account != null && !account.contracts.Any(a => a.contract_id == contractID))
    {
    	contracts newContract = new contracts();
    
    	newContract.contract_id = 5;
    	newContract.contract_name = "Name";
    	newContract.contract_description = "Some Text";
    	
    	account.contracts.Add(newContract);
    
    	controller.Update(account);
    }
    
    // AccountController Update Function.
    public void Update(account item)
    {
    	using (var db = new ClientDbContext())
    	{
    		try
    		{
    			db.accounts.Attach(item); // From reading MSDN it looks like this is the way to do it, but it doesn't create any database objects.
    			db.Entry(item).State = System.Data.Entity.EntityState.Modified;
    			db.SaveChanges();
    		}
    		catch (Exception e)
    		{
    			throw e;
    		}
    	}
    }
    
    // Example #3 in Disconnected State: Works but I don't know if it is the right way, it seems a bit hacky. Only code that changes is the Update function in my controller.
    
    // AccountController Update Function.
    public void UpdatePricingContracts(account item)
    {
    	using (var db = new ClientDbContext())
    	{
    		try
    		{
    			// I don't understand why this is needed.
    			// To me it feels like this would create a new account object, but it doesn't.
    			// It actually STOPS the creation of a duplicate account object.
    			db.accounts.Add(item);
    
    			// I guess because even thought we Add the item, we tell the DbContext it is Unchanged. I thought that was what Attach is for.
    			db.Entry(item).State = System.Data.Entity.EntityState.Unchanged;
    
    			// Marking that the Contracts have changed.
    			foreach (var contract in item.contracts)
    			{
    				db.Entry(contract).State = System.Data.Entity.EntityState.Modified;
    			}
    
    			db.SaveChanges();
    		}
    		catch (Exception e)
    		{
    			throw e;
    		}
    	}
    }

    Tuesday, May 16, 2017 12:04 AM

All replies

  • Hi ismithers,

    If the object named contracts have been in your database, and you want add the record in your junction table and modify the value of contracts, you could refer to the following code.

    using (var db = new Model1()) { var account = db.Accounts .Where(w => w.account_id == 1) // Test Account .FirstOrDefault(); var contract = db.Contracts.Find(5); if (account != null && !account.Contracts.Any(a => a.contract_id == 5)) // Test Contract. { contract.contract_name = "Name";

    contract.contract_description = "Some Text"; account.Contracts.Add(contract); db.SaveChanges(); } }


    Best regards,

    Cole Wu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, May 19, 2017 5:39 AM
    Moderator