如何在实体框架应用程序的基类中实现CRUD操作?

时间:2010-05-18 21:40:50

标签: c# entity-framework dry

我正在使用一个简单的EF / MVC应用程序,我正在尝试实现一些存储库来处理我的实体。我已经设置了一个BaseObject类和一个IBaseRepository接口来处理最基本的操作,所以我不必每次都重复自己:

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();
    }

但后来我发现自己必须在每个存储库中实现3种基本方法(Add,GetById&amp; 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;
        }
    }

如何将这些内容放入我的BaseObject类中,这样我就不会与DRY冲突。

4 个答案:

答案 0 :(得分:1)

您好我遇到了同样的问题。请按照这样的解决方案

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;

                }

            }

        }
    }

}

如果你找到了更好的方法,请告诉我。

答案 1 :(得分:0)

除非您的基类能够实现该接口(然后您可以继承它的实现),否则您每次都会陷入困境。如果每个孩子的步骤不同,那么你不要重复自己,即使它有点像。

作为一个偏离主题的评论,不是在你的基础构造函数中创建db对象,而是可以为自己节省一些痛苦,而依赖注入它。如果您在其中放置任何值得测试的代码,它将使您的存储库更容易进行单元测试。

答案 2 :(得分:0)

您可以使用EF 4中的T4轻松完成此操作。通过更多工作,您可以使用EF 1中的T4进行此操作。

但我建议你不要。 MyEntity.Update()将是一部小说。 EF不允许您将部分更改保存到上下文(如一个特定对象)。所以你的方法会做一些与它看起来完全不同的事情。恕我直言,这个设计正在对抗EF。它还可以通过设计使您的实体具有持久性感知能力。

答案 3 :(得分:0)

这是一个老问题,但它仍然是开放的,所以也许对某人有帮助。我对这种情况的解决方案是使用一个abstrat类,其泛型类型实现了select,insert,update或delete等基本操作。

我的基类看起来像这样:

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();
}

具体示例类

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();
    }
}

测试

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);
        }
    }
}

此代码适用于Visual Studio Community 2013中的Entity Framework 5.