Entityattached is the perfect solution for Error Reporting in Entity Framework.

Source: Internet
Author: User

Entityattached is the perfect solution for Error Reporting in Entity Framework.

When we use Entity Framework for CRUD, in order to improve the query efficiency, NoTracking is generally started, that is, no changes are tracked. The setting code is as follows:

// This is the setting method in DB First mode: aTestEntities db = new aTestEntities (); db. companies. mergeOption = MergeOption. noTracking; // This is the setting method in CODE First and Model First modes: aTestEntities db = new aTestEntities (); db. companies. asNoTracking ();

Although NoTracking is enabled, the query efficiency is improved, but when we perform CUD, sometimes the following errors may occur:

This object cannot be appended because it is already in the context of the object. Objects can be reappended only when they are in the unchanged state.

Because NoTracking is enabled during the query, it indicates that the object to be queried is in the Detached state, and Attach must be performed before CRD, then add, update, and delete operations can be performed. However, in some cases, we cannot guarantee that the CRD entity is Detached, which may cause repeated Attach operations, this leads to report errors or other errors.

To avoid repeated Attach operations, we must have a status that can determine whether the object is Attach. If Attached is already present, we do not need to Attach any more, EF does not have such methods, so I have summarized the following solutions (IsAttached method) to avoid such problems:

Solution 1: When DB First is used, because the entity classes all inherit from EntityObject, we can judge by using the EntityObject. EntityKey attribute.

/// <Summary> /// determine whether the entity has been Attached // </summary> /// <param name = "entity"> </param> // <returns> </returns> public bool IsAttached <TEntity> (TEntity entity) where TEntity: EntityObject {ObjectStateEntry entry = null; if (dbContext. objectStateManager. tryGetObjectStateEntry (entity. entityKey, out entry) {if (entry. state! = EntityState. Detached) {return true ;}} return false ;}

Solution 2: When Model First or Code First is used, because the entity class we designed for ourselves does not inherit from EntityObject by default, we cannot use the above method, however, we can design entity classes using the idea in solution 1. We can define an interface IEntityWithId, and then let all entity classes implement this interface, finally, rewrite solution 1.

Public interface IEntityWithId {Guid Id {get; set ;}} public class EntityClass: IEntityWithId {Guid Id {get; set ;}//... other attributes }//< summary> /// determine whether the entity has been Attached /// </summary> /// <typeparam name = "TEntity"> </typeparam>/ // <param name = "entity"> </param> // <returns> </returns> public bool IsAttached <TEntity> (TEntity entity) where TEntity: IEntityWithId {TEntity localEntity = dbContext. S Et <TEntity> (). Local. Where (t => t. Id = entity. Id). FirstOrDefault (); if (localEntity! = Null) {if (dbContext. Entry (localEntity). State! = EntityState. Detached) {return true ;}} return false ;}

Solution 3: When Model First or Code First is used, if a unified interface is not defined, we cannot use the IsAttached method in solution 2. What should we do? Through viewing object objects in VS Debug, we can find that the object type is not the defined type, but changed to EntityWrapperWithoutRelationships <TEntity>, which has a public field attribute: _ entityWrapper, then, check the field type and find the EntityWrapper class. This class has the EntityKey attribute, which corresponds to the EntityObject in solution 1. the EntityKey attribute has the same type. If we can obtain the EntityKey attribute, we can use the method in solution 1 to make a judgment, the access modifiers of EntityWrapperWithoutRelationships and EntityWrapper classes are internal, which means that we cannot directly use them in our own projects. The only way is to use reflection to dynamically obtain this attribute, the implementation method is as follows:

/// <Summary> /// determine whether the entity has been Attached // </summary> /// <param name = "entity"> </param> // <returns> </returns> private bool IsAttached (TEntity entity) {var objectContext = (IObjectContextAdapter) this. baseContext ). objectContext; ObjectStateEntry entry = null; if (objectContext. objectStateManager. tryGetObjectStateEntry (GetEntityKey (entity), out entry) {if (entry. state! = EntityState. detached) {return true;} return false ;} /// <summary> /// obtain the EntityKey of the object through reflection // </summary> /// <param name = "entity"> </param> // /<returns> </returns> private EntityKey GetEntityKey (TEntity entity) {var entityWrapper = entity. getType (). getField ("_ entityWrapper "). getValue (entity); // obtain the value of field _ entityWrapper var entityWrapperType = entityWrapper. getType (); // obtain the field type var entityKey = entityWrapperType. getProperty ("EntityKey "). getValue (entityWrapper, null); // gets the value of the EntityKey attribute return (EntityKey) entityKey ;}

After implementing the IsAttached method, we don't have to worry about repeated Attach. The method is simple, you only need to call the IsAttached method before updating or deleting the object to determine whether the object is Attached. If not, it is ignored. The code example is as follows:

        public virtual void Update(TEntity entity, bool autoCommit = false)        {            this.ValidateEntity(entity, false);            if (!this.IsAttached(entity))            {                this.objectSet.Attach(entity);                this.baseContext.Entry(entity).State = EntityState.Modified;            }            if (autoCommit)            {                this.Commit();            }        }        public virtual void Remove(TEntity entity, bool autoCommit = false)        {            if (!this.IsAttached(entity))            {                this.objectSet.Attach(entity);            }            this.objectSet.Remove(entity);            if (autoCommit)            {                this.Commit();            }        }

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.