Как я могу реализовать CRUD-операции в базовом классе для приложения платформы лица? - PullRequest
3 голосов
/ 19 мая 2010

Я работаю над простым приложением 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 & 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 ]

1 голос
/ 21 июня 2012

Привет, я столкнулся с той же проблемой. Придумайте решение, подобное этому

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;

                }

            }

        }
    }

}

Пожалуйста, дайте мне знать, если вы нашли лучший способ сделать то же самое

0 голосов
/ 29 апреля 2015

Это старый вопрос, но он все еще открыт, так что, может быть, он кому-нибудь пригодится. Мое решение для этой ситуации заключается в использовании класса abstrat с универсальными типами, реализующими базовые операции, такие как выбор, вставка, обновление или удаление.

Мой базовый класс выглядит так:

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

Этот код работает с Entity Framework 5 в Visual Studio Community 2013.

0 голосов
/ 19 мая 2010

Вы можете легко сделать это с T4 в EF 4. С большей работой вы можете сделать это с T4 в EF 1.

Но я рекомендую не делать этого. MyEntity.Update() будет выдумкой. EF не позволяет вам сохранить часть изменений в контексте (например, один конкретный объект). Таким образом, ваш метод будет делать что-то совсем другое, чем кажется. ИМХО этот дизайн работает против EF. Это также делает ваши сущности сознательными благодаря своему замыслу.

0 голосов
/ 19 мая 2010

Если ваш базовый класс не способен реализовать интерфейс (а затем вы можете унаследовать его реализацию), вы каждый раз сильно зацикливаетесь на написании их.Если шаги для каждого ребенка различны, то вы не повторяете себя, даже если кажется, что это похоже на это.

Как замечание не по теме, вместо создания объекта db в базовом конструкторе вы можетечтобы спасти себя от некоторой боли в будущем, вместо этого добавьте зависимости.Это сделает ваш репозиторий проще для модульного тестирования, если вы поместите туда какой-либо код, достойный тестирования.

...