动态实例化通用存储库以及如何将实体基类添加到Entity Framework

时间:2016-03-25 14:39:59

标签: c# entity-framework

以下是使用EF6实现存储库模式。我想以下列方式使用通用存储库,从而无需为每种类型

创建存储库
_unitOfWork.Repository(entityName).Insert(entityName)

public interface IRepository<T> where T : class
{
    //--Search Operations
    IEnumerable<T> Get();
    T GetByID(object id);
    void Insert(T entity);
    void Delete(object id);
    void Delete(T entityToDelete);
    void Update(T entityToUpdate);
}

我创建了一个所有实体都将继承的基类。这个基类的意图是我可以用这个基类引用所有实体。

public class IRepositoryEntity
{
}

以下是Entity Framework生成的代码,我从IRepositoryEntity

继承了这个实体
public partial class Client_Entity: IRepositoryEntity
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Client_Entity()
    {
    }

    public int Id { get; set; }
}

以下是通用存储库

public class GenericRepository<IRepositoryEntity> : IRepository<IRepositoryEntity> where IRepositoryEntity : class
{
    #region Private member variables...
    internal ConsularDB_March2016Entities Context;
    internal DbSet<IRepositoryEntity> DbSet;
    #endregion

    #region Public Constructor...
    /// <summary>
    /// Public Constructor,initializes privately declared local variables.
    /// </summary>
    /// <param name="context"></param>
    public GenericRepository(ConsularDB_March2016Entities context)
    {
        this.Context = context;
        this.DbSet = context.Set<IRepositoryEntity>();
    }
    ///// <summary>
    ///// Public Constructor,initializes privately declared local variables.
    ///// </summary>
    ///// <param name="context"></param>
    //public GenericRepository()
    //{
    //    this.Context = context;
    //    this.DbSet = context.Set<IRepositoryEntity>();
    //}
    #endregion

    #region Public member methods...

    /// <summary>
    /// generic Get method for Entities
    /// </summary>
    /// <returns></returns>
    public  IEnumerable<IRepositoryEntity> Get()
    {
        IQueryable<IRepositoryEntity> query = DbSet;
        return query.ToList();
    }
}

以下是IUnitOfWork界面及其实现

public interface IUnitOfWork
{
    #region Properties
    GenericRepository<Client_Entity> ClientRepository { get; }
    #endregion

    #region Public methods
    /// <summary>
    /// Save method.
    /// </summary>
    void Save();
    GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity);
    #endregion
}

/// <summary>
/// Unit of Work class responsible for DB transactions
/// </summary>
public class UnitOfWork : IDisposable, IUnitOfWork
{
    #region Private member variables...

    private March2016Entities _context = null;
    private GenericRepository<Client_Entity> _clientRepository;
    #endregion

    public UnitOfWork()
    {
        _context = new March2016Entities();
    }

     #region Public member methods...
    /// <summary>
    /// Save method.
    /// </summary>
    public void Save()
    {
        try
        {
            _context.Configuration.ValidateOnSaveEnabled = false;
            _context.SaveChanges();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            var context = ((IObjectContextAdapter)_context).ObjectContext;
            var refreshobjects = _context.ChangeTracker.Entries().Select(c => c.Entity).ToList();
            context.Refresh(System.Data.Entity.Core.Objects.RefreshMode.StoreWins, refreshobjects);
            _context.SaveChanges();
        }
        catch (DbEntityValidationException e)
        {

            var outputLines = new List<string>();
            foreach (var eve in e.EntityValidationErrors)
            {
                outputLines.Add(string.Format("{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State));
                foreach (var ve in eve.ValidationErrors)
                {
                    outputLines.Add(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));
                }
            }
            System.IO.File.AppendAllLines(@"C:\errors.txt", outputLines);

            throw e;
        }

    }

    #endregion

    #region Implementing IDiosposable...

    #region private dispose variable declaration...
    private bool disposed = false;
    #endregion

    /// <summary>
    /// Protected Virtual Dispose method
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                Debug.WriteLine("UnitOfWork is being disposed");
                _context.Dispose();
            }
        }
        this.disposed = true;
    }

    /// <summary>
    /// Dispose method
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion
    #region GenericMembers
    Dictionary<string, GenericRepository<IRepositoryEntity>> repostories = new Dictionary<string, GenericRepository<IRepositoryEntity>>();

    /// <summary>
    /// Generic Repository method which checks the repository is available if not,
    /// it sets it up.
    /// </summary>
    /// <param name="entity">Entity</param>
    /// <returns>Repository to use.</returns>
    public GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity)
    {
        string index = entity.GetType().ToString();

        if (!repostories.ContainsKey(index))
        {

            //Reflections to create the repoositiory if it is not needed.
            Type type1 = typeof(GenericRepository<IRepositoryEntity>);
            Type[] typeArgs = { entity.GetType() };

            Type constructed = type1.MakeGenericType(typeArgs);
            object o = Activator.CreateInstance(constructed, this._context);

            //if (o is GenericRepository<IRepositoryEntity>)
            //{
            object genericRepo = (object)o;
            var rep = (GenericRepository<IRepositoryEntity>)genericRepo;
            //rep.Context = this._context;
            repostories.Add(index, rep);
            //}
        }
        return this.repostories[index];
    }
    #endregion  
}

我正在尝试在以下函数中动态创建GenericRepository列表

public GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity)

在创建实例时,它抛出以下异常

  

mscorlib.dll中出现“System.InvalidOperationException”类型的异常,但未在用户代码中处理

     

附加信息:GenericRepository`1 [IRepositoryEntity]不是GenericTypeDefinition。 MakeGenericType只能在Type.IsGenericTypeDefinition为true的类型上调用。

我理解异常,但不确定如何更改实现,以便我能够实现所需的功能。另外,我如何将IRepositoryEntity添加到EF模型中,因为它表示它不是模型的一部分。

public void ValidateGenericEntityInsert(IRepositoryEntity entityName)
{
        IRepositoryEntity entity = (IRepositoryEntity)Activator.CreateInstance(entityName);
        _unitOfWork.Repository(entityName).Insert(entityName);

        // int generatedId = GetPropertyFromEntity(entity, en => en.Id);
        int generatedId = (int)GetPropertyFromEntity(entityName, "Id");

        Assert.That(generatedId, Is.GreaterThan(0));
}

0 个答案:

没有答案