开发者

How can I implement CRUD operations in a base class for an entity framework app?

开发者 https://www.devze.com 2022-12-30 14:17 出处:网络
I\'m working a simple EF/MVC app and I\'m trying to implement some Repositories to handle my entities. I\'ve set 开发者_C百科up a BaseObject Class and a IBaseRepository Interface to handle the most ba

I'm working a simple EF/MVC app and I'm trying to implement some Repositories to handle my entities. I've set 开发者_C百科up a BaseObject Class and a IBaseRepository Interface to handle the most basic operations so I don't have to repeat myself each time:

public abstract class BaseObject<T>
    {
        public XA.Model.Entities.XAEntities db;
        public BaseObject()
        {
            db = new Entities.XAEntities();
        }

        public BaseObject(Entities.XAEntities cont)
        {
            db = cont;
        }

        public void Delete(T entity)
        {
            db.DeleteObject(entity);
            db.SaveChanges();
        }

        public void Update(T entity)
        {
            db.AcceptAllChanges();
            db.SaveChanges();
        }
   }

    public interface IBaseRepository<T>
    {
        void Add(T entity);

        T GetById(int id);
        IQueryable<T> GetAll();
    }

But then I find myself having to implement 3 basic methods in every Repository ( Add, GetById & GetAll):

public class AgencyRepository : Framework.BaseObject<Agency>, Framework.IBaseRepository<Agency>
    {
        public void Add(Agency entity)
        {
            db.Companies.AddObject(entity);
            db.SaveChanges();
        }
        public Agency GetById(int id)
        {
            return db.Companies.OfType<Agency>().FirstOrDefault(x => x.Id == id);
        }
        public IQueryable<Agency> GetAll()
        {
            var agn = from a in db.Companies.OfType<Agency>()
                      select a;
            return agn;
        }
    }

How can I get these into my BaseObject Class so I won't run in conflict with DRY.


Hi I was facing same problem.Come up with solution like this

namespace ABC
{
    public class EntitiesRepository<T> : IDisposable where T : class
    {
        private ObjectContext _context;

        /// <summary>
        /// The IObjectSet that represents the current entity.
        /// </summary>
        private ObjectSet<T> _objectSet;

        public OperationStatus status { get; set; }

        /// <summary>
        /// Initializes a new instance of the DataRepository class
        /// </summary>
        public BilderQuizEntitiesRepository()
        {
            _context = new Entities();  //DBContext

            _objectSet = _context.CreateObjectSet<T>();
         }

        public T Select(int id)
        {
            EntityKey key = GetEntityKey(id);

            return (T)_context.GetObjectByKey(key);
        }

        public void Delete(T entity)
        {
            try
            {
                if (entity == null)
                {

                    throw new ArgumentNullException("entity");
                }

                EntityKey key = GetEntitySpecificKey(entity);
                T attachEntity = (T)_context.GetObjectByKey(key);
                _objectSet.DeleteObject(attachEntity);
                SaveChanges();                
            }
            catch
            {

            }

        }       

        public void Delete(int id)
        {
            EntityKey key = GetEntityKey(id);
            Delete((T)_context.GetObjectByKey(key));
            SaveChanges();
        }

        public void Update(T entity)
        {
            try
            {
                if (entity == null)
                {

                    throw new ArgumentNullException("entity");
                }

                EntityKey key = GetEntitySpecificKey(entity);
                T attachEntity = (T)_context.GetObjectByKey(key);
                _objectSet.Attach(attachEntity);
                _objectSet.ApplyCurrentValues(entity);
                SaveChanges();

            }
            catch
            {

            }

        }       

        /// <summary>
        /// Returns Entity Key 
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        private EntityKey GetEntityKey(object keyValue) //Get EnrityKey
        {
            var entitySetName = _context.DefaultContainerName + "." + _objectSet.EntitySet.Name;
            var keyPropertyName = _objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
            var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
            return entityKey;
        }

        /// <summary>
        /// Returns Entity Key 
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        private EntityKey GetEntitySpecificKey(T entity) //Get EnrityKey
        {
            Type objType = typeof(T);
            var keyPropertyName = _objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
            var pi = objType.GetProperty(keyPropertyName);
            var keyValue = pi.GetValue(entity, null);
            var entitySetName = _context.DefaultContainerName + "." + _objectSet.EntitySet.Name;

            var entityKey = new EntityKey(entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
            return entityKey;
        }

        private string GetPrimaryKeyValue(T entity)
        {
            Type objType = typeof(T);
            var keyPropertyName = _objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
            var pi = objType.GetProperty(keyPropertyName);
            var keyValue = pi.GetValue(entity, null);
            return keyValue.ToString();
        }

        /// <summary>
        /// Saves all context changes
        /// </summary>
        public bool SaveChanges()
        {
            return _context.SaveChanges() > 0 ? true : false;
        }

        /// <summary>
        /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
        /// </summary>
        public void Dispose()
        {

            Dispose(true);

            GC.SuppressFinalize(this);

        }

        /// <summary>
        /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
        /// </summary>
        /// <param name="disposing">A boolean value indicating whether or not to dispose managed resources</param>
        protected virtual void Dispose(bool disposing)
        {

            if (disposing)
            {

                if (_context != null)
                {

                    _context.Dispose();

                    _context = null;

                }

            }

        }
    }

}

Please let me know if u found a better way to do the same


Unless your base class is able to implement the interface (and then you can inherit it's implementation) you're prety much stuck writing them each time. If the steps are different for each child, then your not repeating yourself, even though it kinda feels like it.

As an off topic remark, rather than creating the db object in your base constructor, you may be able to save your self some pain down the road and dependency inject it instead. It will make your repository easier to unit test if your putting any code in there that's worthy of testing.


You can easily do this with T4 in EF 4. With more work, you can do it with T4 in EF 1.

But I recommend that you don't. MyEntity.Update() will be a fiction. The EF doesn't allow you to save part of the changes to a context (like one specific object). So your method will do something very different than it appears to do. IMHO this design is working against the EF. It also makes your entities persistence-aware by design.


This is an old question but it stills open, so maybe it is helpfull for someone. My solution for this situation is using an abstrat class with generic types implementing basic operations like select, insert, update or delete.

My base class look like this:

public abstract class MyContext<T, key> : IDisposable where T : class {

    private DbEntities db;    //my database context
    private DbSet<T> entities;  //specific set

    protected MyContext(DbEntities db) {
        entities = db.Set<T>();
        this.db = db;
    }

    public T Add(T entity) {
        entities.Add(entity);
        db.SaveChanges();
        return entity;
    }

    public T Get(key id) {
        return entities.Find(id);
    }

    public List<T> GetAll() {
        return entities.ToList();
    }

    public void Delete(key id) { 
        T objectToDelete=entities.Find(id);
        if(objectToDelete!=null){
            entities.Remove(objectToDelete);
            db.SaveChanges();
        }  
    }

    public void Delete(T entity) {
        entities.Remove(entity);
        db.SaveChanges();
    }

    public void Delete(List<T> items) {
        foreach (T entity in items) {
            entities.Remove(entity);
        }
        db.SaveChanges();
    }

    public void Update(T entity) {
        entities.Attach(entity);
        db.Entry(entity).State = EntityState.Modified;
        db.SaveChanges();
    }

    public abstract void Dispose();
}

Concrete example class

public class PermissionDataBase : MyContext<Permission,int>{  
    //Mapped class Permission where the key is int

    private DbEntities db=null;

    public PermissionDataBase(DbEntities db):base(db) {
        this.db = db;
    }

    //Additional methods (if required)
    public Permission FindByName(string name) {
        return db.Permissions.FirstOrDefault(p => p.Name == name);
    }

    public override void Dispose() {
        db.Dispose();
    }
}

Testing

public class ModelsTest {
    [TestMethod]
    public void TestMethod1() {
        DbEntities db = new DbEntities();
        using (PermissionDataBase permissionDb = new PermissionDataBase(db)) {

            Permission newEntity = new Permission() {
                Name = "Test1"
            };

            permissionDb.Add(newEntity);

            Assert.IsTrue(newEntity.Id > 0);
        }
    }

    [TestMethod]
    public void TestMethod2() {
        DbEntities db = new DbEntities();
        using (PermissionDataBase permissionDb = new PermissionDataBase(db)) {

            List<Permission> items = permissionDb.GetAll();
            Assert.IsTrue(items.Count > 0);
        }
    }

    [TestMethod]
    public void TestMethod3() {
        DbEntities db = new DbEntities();
        using (PermissionDataBase permissionDb = new PermissionDataBase(db)) {

            Permission toDelete = permissionDb.Get(3);  //Assuming id=3 exists
            permissionDb.Delete(toDelete);

            Permission deleted = permissionDb.Get(3);
            Assert.IsNull(deleted);
        }
    }
}

This code works with Entity Framework 5 in Visual Studio Community 2013.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号