Wednesday, October 6, 2010

A generic Data Access Layer using ADO.Net entity framework for N-Tier application

If you work with ADO.Net, you know object context is mainly responsible to track changes of entity in an object graph. So, ADO.Net entity framework works fine as long as your entity is connected to object context. However, in N-Tier application/web application, the entity has to be disconnected from object context. In order to work with disconnected entity, entity framework doesn’t have any straight forward way before the entity framework team introduces self-tracking entities.

I have created a simple data access layer for disconnected entities using the self-tracking feature of Entity framework. The following code snippet shows generic implementation for CRUD operations:

public class MallInteractiveMapEntities2 : MallInteractiveMapEntities
    {
        private static Dictionary<string, Action<MallInteractiveMapEntities2, object>>
            _AddToMethodCache =
                new Dictionary<string, Action<MallInteractiveMapEntities2, object>>();

        public MallInteractiveMapEntities2():base()
        {
            if(_AddToMethodCache.Count == 0)
            {
                lock(_AddToMethodCache)
                {
                    _AddToMethodCache.Add(typeof (Mall).Name,
                                          (context, entity) => context.Malls.ApplyChanges(entity as Mall));
                    _AddToMethodCache.Add(typeof(Floor).Name,
                                          (context, entity) => context.Floors.ApplyChanges(entity as Floor));
                }
            }
        }

        public void AddTo<TEntity>(TEntity entity)
        {
            _AddToMethodCache[typeof(TEntity).Name](this, entity);
        }

        public bool ApplyChangesToEntity<TEntity>(TEntity entity) where TEntity : IObjectWithChangeTracker
        {
            try
            {
                AddTo<TEntity>(entity);
                SaveChanges();
            }
            catch
            {
                return false;
            }
            return true;
        }

public bool ApplyChangesToEntityList<TEntity>(IEnumerable<TEntity> entities) where TEntity : IObjectWithChangeTracker
        {
            try
            {
                entities.AsParallel().ForAll(AddTo);
                SaveChanges();
            }
            catch
            {
                return false;
            }
            return true;
        }
      
    }

MallInteractiveMapEntities class is generated from Entity framework designer for a specific database. MallInteractiveMapEntities2 class which is inherited from MallInteractiveMapEntities has some methods to perform the CRUD operations.

To illustrate the use of the above class, consider we have two entities named “Map” and “Floor”. “Floor” is the child of “Map” and the relation is one to many. In order to create(C) Map and Floor, use the following pseudo code.

  Mall mall = new Mall();
  mall.Name = "American Shopping Mall";

            Floor floor1 = new Floor();
            floor1.Name = "Ground Floor";
            mall.Floors.Add(floor1);

            Floor floor2 = new Floor();
            floor2.Name = "First Floor";
            mall.Floors.Add(floor2);


            using (MallInteractiveMapEntities2 context = new MallInteractiveMapEntities2())
            {
                context.ApplyChangesToEntity<Mall>(mall);
            }

When you instantiate an entity, it will be marked as an added state.

To update an entity with child entities, use the following pseudo code:

      Mall mall = new Mall();
      mall.Id = 1;
      mall.Name = "American Shopping Mall";
      mall.MarkAsModified();
 
      Floor floor1 = new Floor();
      floor1.Name = "Ground Floor";
      floor1.MallId = mall.Id;
      floor1.MarkAsModified();
      mall.Floors.Add(floor1);

      Floor floor2 = new Floor();
      Floor2.MallId = mall.Id;
      Floor2.MarkAsModified();
      floor2.Name = "First Floor";
      mall.Floors.Add(floor2);


      using (MallInteractiveMapEntities2 context = new MallInteractiveMapEntities2())
            {
                context.ApplyChangesToEntity<Mall>(mall);
            }


Here, you have to mark the entity as a modified state. You also have to set the parent id to a child entity.

To delete (D) an entity, simply mark each entity as a deleted by using the “MarkAsDeleted()” method.

Self tracking is a promising feature of Entity framework. By using this feature, you can create a data access layer for disconnected entity of ADO.Net entity framework.

Hope this help!

No comments: