ADO.Net Entity Framework An entity object cannot be referenced by multiple instances of IEntityChangeTracker

后端 未结 3 1290
迷失自我
迷失自我 2020-12-03 03:23

I am trying to save my contact, which has references to ContactRelation (just the relationship of the contact, married, single, etc) and Country. But everytime I try to save

相关标签:
3条回答
  • 2020-12-03 03:49

    I've seen this before, you may have to convert the Reference field to an EntityKey before saving and then Load it after its saved. Try this code instead:

    public Contact CreateContact(Contact contact){
        contact.ConvertContactRelationToReference();
        _entities.AddToContact(contact); 
        //throws the exception
        _entities.SaveChanges();
        contact.ContactRelation.Load();
        return contact;
    }
    
    public partial class Contact
    {
      public void ConvertContactRelationToReference()
      {
        var crId = ContactRelation.Id;
        ContactRelation = null;
        ContactRelationReference.EntityKey = new EntityKey("MyEntities.ContactRelations", "Id", crId);
      }
    }
    

    Of course, some of this code may need to be changed depending on your exact database structure.

    0 讨论(0)
  • 2020-12-03 03:59

    [Update]
    Because L2E is used you need to save all the linked objects first before you can save the main object. Which makes sense otherwise you would create (in my example) an artist without it's contact object. This isn't allowed by the database design.
    [/Update]

    Here's my implementation which worked.

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create([Bind(Exclude = "Id")] Artist artist, [Bind(Prefix = "Contact")] Contact contact, [Bind(Prefix = "Country")] Country country, [Bind(Prefix = "ContactRelationship")] ContactRelationship contactRelationship)
    {
        ViewData["Countries"] = new SelectList(new CountryService(_msw).ListCountries().OrderBy(c => c.Name), "ID", "Name");
        ViewData["ContactRelationships"] = new SelectList(new ContactRelationshipService(_msw).ListContactRelationships().OrderBy(c => c.ID), "ID", "Description");
    
        country = _countryService.GetCountryById(country.ID);
        contact.Country = country;
        contactRelationship = _contactRelationshipService.GetContactRelationship(contactRelationship.ID);
        contact.ContactRelationship = contactRelationship;
        if(_contactService.CreateContact(contact)){
            artist.Contact = contact;
            if (_service.CreateArtist(artist))
                return RedirectToAction("Index");        
        }
        return View("Create");
    }
    

    And then in my ContactRepository :

    public Contact CreateContact(Contact contact)
    {
        _entities.AddToContact(contact); //no longer throws the exception
        _entities.SaveChanges();
        return contact ;
    }
    

    I also found on this website that it is best to keep the same context throughout the application so I'm now using a special Data class for this:

    Rick Strahl and Samuel Maecham have taught me that you should keep your datacontext per user per request. Which means putting it in the HttpContext for web applications. Read all about it here

    public class Data
    {
        public static MyDBEntities MyDBEntities
        {
            get
            {
                if (HttpContext.Current != null && HttpContext.Current["myDBEntities"] == null)
                {
                    HttpContext.Current["myDBEntities"] = new MyDBEntities ();
                }
                return HttpContext.Current["myDBEntities"] as MyDBEntities;
            }
            set { 
                if(HttpContext.Current != null)
                    HttpContext.Current["myDBEntities"] = value; 
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 04:05

    Ummm I wonder if someone can please sanity check my solution. It's very similar to the accepted answer below but after reading Rick Strahl's blog about DataContext Life Management I am worried that this isn't a thread-safe solution for a web application.

    I also got round the instance where I was receiving this error message by accessing my object context using the singleton pattern.

    I added the following to MyObjectContext class:

    // singleton
    private static MyObjectContext context;
    public static MyObjectContext getInstance()
    {
        if (context == null)
        {
            context = new MyObjectContext ();
        }
        return context;
    } 
    

    And in my per-entity repository mapper instead of instantiating a new instance of MyObjectContext I use

    var db = MyObjectContext.getInstance();
    

    Am I being stupid here? It seems to work.

    0 讨论(0)
提交回复
热议问题