(译文)MVC通用仓储类

Generic Repository Pattern MVC

Generic Repository Pattern MVC

原文链接:http://www.codeproject.com/Articles/1095323/Generic-Repository-Pattern-MVC

良好的架构师任何项目的核心,开发人员一直在寻找一个牛X的架构,它能减少重复代码,分离数据访问与业务逻辑。因此,我们需要在MVC中使用EF创建一个泛型仓储类。如果不了解EF,去这里学习。在开始之前,我们需要了解什么是仓储模式,为什么使用仓储模式。

仓储模式和工作单元

简言之,仓储模式意味着,数据访问层与业务逻辑层之间的抽象,这是非常有利于单元测试或TDD。通过使用仓储模式,你的系统会更加松散耦合。

在开发过程中,我们通常为每个仓储或实体创建一个接口。例如,我们为Student这个实体创建一个接口约束(IStudentInterface),定义所有的CRUD操作,同时创建另一个类(StudentRepository)实现接口中所定义的所有方法。当我们在控制器中实例化仓储类的时候,我们将使用实现了对应接口的类的引用。当控制器在运行的时候,它将调用在EF基础上工作的仓储类。

当对控制器进行单元测试的时候,我们可以操作仓储类的具体数据实现,例如内存数据集。这样我们可以使用伪数据进行单元测试。

如果你想了解详细的实现,可以参照如下链接:

getting started with ef 5 using mvc 4 / implementing the repository and unit of work patterns in an asp.net mvc application

不利因素

每次我们都需要为实体创建仓储类,导致代码冗余

代码实现

现在我们仅仅需要一个数据访问类,介绍一些实体和执行必要的操作,例如CRUD.在学习了很多文章、理论和示例代码后,我获得了一个很好的通用的仓储模式的实现。

我的代码在很大程度上基于Huy Nguyen的博客。请参阅以下链接

entity-framework-4-poco-repository-and-specification-pattern

entity-framework-poco-repository-and-specification-pattern-upgraded-to-ef-5

我修改了很多实现代码同时添加了一些在项目中常用的代码实现。现在我能使用这个类库在任何项目。下面是文件结构:

Mayur.DAL – 通用仓储和公共方法类库

  • Core – 文件夹

    • GlobalCommonHelper.cs – 一个为每个项目提供大部分公共方法的抽象类
  • Repository – 文件夹
    • IRepository.cs – 通用仓储接口
    • Repository.cs – 通用仓储实现类,继承与仓储接口
    • IUnitOfWork.cs – 工作单元接口.
    • UnitOfWork.cs – 实现了EF的SaveChanges()方法。工作单元类保证我们在对数据库执行事务性的插入、更新、删除操作时,直到我们执行Savechanges()方法以后EF才会提交所做的修改。

Mayur.Web – MVC Web项目

  • Controller – 文件夹

    • HomeController.cs – 包含CRUD动作的控制器
  • Core – 文件夹
    • CommonHelper.cs – 继承于 Mayur.DAL.Core.GlobalCommonHelper.cs which 包含MVC项目中相关的公共方法。
  • Model – 文件夹
    • Student.cs – 实体类
  • Views – Folder
    • Index.chtml – 不用说了吧都
    • Create.chtml – Create new student html
    • Edit.cshtml – Update student info html
    • Delete.cshtml – Delete student info html

让我们简单了解下DAL中每个文件的作用:

Repository 文件夹: 在这个文件夹,包含所有的数据访问逻辑。有4个文件, 2个接口文件,两个接口的实现类

  1. IRepository 接口

     public interface IRepository : IDisposable
        {
            /// <summary>
            /// 获取工作单元
            /// </summary>
            /// <value>The unit of work.</value>
            IUnitOfWork UnitOfWork { get; }
    
            /// <summary>
            ///     Gets entity by key.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="keyValue">The key value.</param>
            /// <returns></returns>
            TEntity GetByKey<TEntity>(object keyValue) where TEntity : class;
    
            /// <summary>
            ///     Gets the query.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <returns></returns>
            IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class;
    
            /// <summary>
            ///     Gets the query.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="predicate">The predicate.</param>
            /// <returns></returns>
            IQueryable<TEntity> GetQuery<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class;
    
            /// <summary>
            ///     Gets all.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <returns></returns>
            IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class;
    
            /// <summary>
            ///     Gets the specified order by.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <typeparam name="TOrderBy">The type of the order by.</typeparam>
            /// <param name="orderBy">The order by.</param>
            /// <param name="pageIndex">Index of the page.</param>
            /// <param name="pageSize">Size of the page.</param>
            /// <param name="sortOrder">The sort order.</param>
            /// <returns></returns>
            IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex,int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class;
    
            /// <summary>
            ///     Gets the specified criteria.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <typeparam name="TOrderBy">The type of the order by.</typeparam>
            /// <param name="criteria">The criteria.</param>
            /// <param name="orderBy">The order by.</param>
            /// <param name="pageIndex">Index of the page.</param>
            /// <param name="pageSize">Size of the page.</param>
            /// <param name="sortOrder">The sort order.</param>
            /// <returns></returns>
            IEnumerable<TEntity> Get<TEntity, TOrderBy>(Expression<Func<TEntity, bool>> criteria,
                Expression<Func<TEntity,
                TOrderBy>> orderBy,
                int pageIndex,
                int pageSize,
                SortOrder sortOrder = SortOrder.Ascending) where TEntity : class;
    
            /// <summary>
            ///     Gets one entity based on matching criteria
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            /// <returns></returns>
            TEntity Single<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class;
    
            /// <summary>
            ///     Firsts the specified predicate.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="predicate">The predicate.</param>
            /// <returns></returns>
            TEntity First<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class;
    
            /// <summary>
            ///     Finds entities based on provided criteria.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            /// <returns></returns>
            IEnumerable<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class;
    
            /// <summary>
            ///     Finds one entity based on provided criteria.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            /// <returns></returns>
            TEntity FindOne<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class;
    
            /// <summary>
            ///     Counts the specified entities.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <returns></returns>
            int Count<TEntity>() where TEntity : class;
    
            /// <summary>
            ///     Counts entities with the specified criteria.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            /// <returns></returns>
            int Count<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class;
    
            /// <summary>
            ///     Adds the specified entity.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="entity">The entity.</param>
            void Add<TEntity>(TEntity entity) where TEntity : class;
    
            /// <summary>
            ///     Attaches the specified entity.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="entity">The entity.</param>
            void Attach<TEntity>(TEntity entity) where TEntity : class;
    
            /// <summary>
            ///     Updates changes of the existing entity.
            ///     The caller must later call SaveChanges()
            ///     on the repository explicitly to save the entity to database
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="entity">The entity.</param>
            void Update<TEntity>(TEntity entity) where TEntity : class;
    
            /// <summary>
            ///     Deletes the specified entity.
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="entity">The entity.</param>
            void Delete<TEntity>(TEntity entity) where TEntity : class;
    
            /// <summary>
            ///     Deletes one or many entities matching the specified criteria
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            void Delete<TEntity>(Expression<Func<TEntity, bool>> criteria) where TEntity : class;
    
            /// <summary>
            ///     Deletes entities which satisfy specificatiion
            /// </summary>
            /// <typeparam name="TEntity">The type of the entity.</typeparam>
            /// <param name="criteria">The criteria.</param>
            //void Delete<TEntity>
            //(ISpecification<TEntity> criteria) where TEntity : class;
        }
  2. Repository 类
       1:     /// <summary>
       2:     ///     Generic repository Class
       3:     /// </summary>
       4:     public partial class Repository : IRepository, IDisposable
       5:     {
       6:         //Private Variables
       7:         private bool bDisposed;
       8:         private DbContext context;
       9:         private IUnitOfWork unitOfWork;
      10:   
      11:         #region Contructor Logic
      12:   
      13:         /// <summary>
      14:         /// Initializes a new instance of the
      15:         /// <see cref="Repository<TEntity>"/> class.
      16:         /// </summary>
      17:         public Repository()
      18:         {
      19:   
      20:         }
      21:   
      22:         /// <summary>
      23:         ///     Initializes a new instance of the
      24:         /// <see cref="Repository<TEntity>" /> class.
      25:         /// </summary>
      26:         /// <param name="context">The context.</param>
      27:         public Repository(DbContext contextObj)
      28:         {
      29:             if (contextObj == null)
      30:                 throw new ArgumentNullException("context");
      31:             this.context = contextObj;
      32:         }
      33:   
      34:         public Repository(ObjectContext contextObj)
      35:         {
      36:             if (this.context == null)
      37:                 throw new ArgumentNullException("context");
      38:             context = new DbContext(contextObj, true);
      39:         }
      40:   
      41:         public void Dispose()
      42:         {
      43:             Close();
      44:         }
      45:   
      46:         #endregion
      47:   
      48:         #region Properties
      49:   
      50:         //DbContext Property
      51:         protected DbContext DbContext
      52:         {
      53:             get
      54:             {
      55:                 if (context == null)
      56:                     throw new ArgumentNullException("context");
      57:   
      58:                 return context;
      59:             }
      60:         }
      61:   
      62:         //Unit of Work Property
      63:         public IUnitOfWork UnitOfWork
      64:         {
      65:             get
      66:             {
      67:                 if (unitOfWork == null)
      68:                 {
      69:                     unitOfWork = new UnitOfWork(DbContext);
      70:                 }
      71:                 return unitOfWork;
      72:             }
      73:         }
      74:   
      75:         #endregion
      76:   
      77:         #region Data Display Methods
      78:   
      79:         //Helper Method tp create Query [IQuerable]
      80:   
      81:         public TEntity GetByKey<TEntity>(object keyValue) where TEntity : class
      82:         {
      83:             EntityKey key = GetEntityKey<TEntity>(keyValue);
      84:   
      85:             object originalItem;
      86:             if (((IObjectContextAdapter)DbContext).
      87:             ObjectContext.TryGetObjectByKey(key, out originalItem))
      88:             {
      89:                 return (TEntity)originalItem;
      90:             }
      91:   
      92:             return default(TEntity);
      93:         }
      94:   
      95:         public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
      96:         {
      97:             string entityName = GetEntityName<TEntity>();
      98:             return ((IObjectContextAdapter)DbContext).
      99:             ObjectContext.CreateQuery<TEntity>(entityName);
     100:         }
     101:   
     102:         public IQueryable<TEntity> GetQuery<TEntity>
     103:         (Expression<Func<TEntity, bool>> predicate) where TEntity : class
     104:         {
     105:             return GetQuery<TEntity>().Where(predicate);
     106:         }
     107:   
     108:   
     109:         //All Readonly Display or fetch data methods.
     110:         public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class
     111:         {
     112:             return GetQuery<TEntity>().AsEnumerable();
     113:         }
     114:   
     115:         public IEnumerable<TEntity> Get<TEntity, TOrderBy>
     116:         (Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex,
     117:             int pageSize, SortOrder sortOrder = SortOrder.Ascending) where TEntity : class
     118:         {
     119:             if (sortOrder == SortOrder.Ascending)
     120:             {
     121:                 return GetQuery<TEntity>()
     122:                     .OrderBy(orderBy)
     123:                     .Skip((pageIndex - 1) * pageSize)
     124:                     .Take(pageSize)
     125:                     .AsEnumerable();
     126:             }
     127:             return
     128:                 GetQuery<TEntity>()
     129:                     .OrderByDescending(orderBy)
     130:                     .Skip((pageIndex - 1) * pageSize)
     131:                     .Take(pageSize)
     132:                     .AsEnumerable();
     133:         }
     134:   
     135:         public IEnumerable<TEntity> Get<TEntity,
     136:         TOrderBy>(Expression<Func<TEntity, bool>> criteria,
     137:             Expression<Func<TEntity, TOrderBy>> orderBy, int pageIndex, int pageSize,
     138:             SortOrder sortOrder = SortOrder.Ascending) where TEntity : class
     139:         {
     140:             if (sortOrder == SortOrder.Ascending)
     141:             {
     142:                 return GetQuery(criteria).
     143:                     OrderBy(orderBy).
     144:                     Skip((pageIndex - 1) * pageSize).
     145:                     Take(pageSize)
     146:                     .AsEnumerable();
     147:             }
     148:             return
     149:                 GetQuery(criteria)
     150:                     .OrderByDescending(orderBy)
     151:                     .Skip((pageIndex - 1) * pageSize)
     152:                     .Take(pageSize)
     153:                     .AsEnumerable();
     154:         }
     155:   
     156:         public TEntity Single<TEntity>
     157:         (Expression<Func<TEntity, bool>> criteria) where TEntity : class
     158:         {
     159:             return GetQuery<TEntity>().Single<TEntity>(criteria);
     160:         }
     161:   
     162:         public TEntity First<TEntity>
     163:         (Expression<Func<TEntity, bool>> predicate) where TEntity : class
     164:         {
     165:             return GetQuery<TEntity>().First(predicate);
     166:         }
     167:   
     168:         public IEnumerable<TEntity> Find<TEntity>
     169:         (Expression<Func<TEntity, bool>> criteria) where TEntity : class
     170:         {
     171:             return GetQuery<TEntity>().Where(criteria);
     172:         }
     173:   
     174:         public TEntity FindOne<TEntity>
     175:         (Expression<Func<TEntity, bool>> criteria) where TEntity : class
     176:         {
     177:             return GetQuery<TEntity>().Where(criteria).FirstOrDefault();
     178:         }
     179:   
     180:         public int Count<TEntity>() where TEntity : class
     181:         {
     182:             return GetQuery<TEntity>().Count();
     183:         }
     184:   
     185:         public int Count<TEntity>
     186:         (Expression<Func<TEntity, bool>> criteria) where TEntity : class
     187:         {
     188:             return GetQuery<TEntity>().Count(criteria);
     189:         }
     190:   
     191:         #endregion
     192:   
     193:         #region Data Transactional Methods
     194:   
     195:         public void Add<TEntity>(TEntity entity) where TEntity : class
     196:         {
     197:             if (entity == null)
     198:             {
     199:                 throw new ArgumentNullException("entity");
     200:             }
     201:             DbContext.Set<TEntity>().Add(entity);
     202:         }
     203:   
     204:         public void Attach<TEntity>(TEntity entity) where TEntity : class
     205:         {
     206:             if (entity == null)
     207:             {
     208:                 throw new ArgumentNullException("entity");
     209:             }
     210:   
     211:             DbContext.Set<TEntity>().Attach(entity);
     212:         }
     213:   
     214:         public void Update<TEntity>(TEntity entity) where TEntity : class
     215:         {
     216:             string fqen = GetEntityName<TEntity>();
     217:   
     218:             object originalItem;
     219:             EntityKey key =
     220:             ((IObjectContextAdapter)DbContext).ObjectContext.CreateEntityKey(fqen, entity);
     221:             if (((IObjectContextAdapter)DbContext).ObjectContext.TryGetObjectByKey
     222:             (key, out originalItem))
     223:             {
     224:                 ((IObjectContextAdapter)DbContext).ObjectContext.ApplyCurrentValues
     225:                 (key.EntitySetName, entity);
     226:             }
     227:         }
     228:   
     229:         public void Delete<TEntity>(TEntity entity) where TEntity : class
     230:         {
     231:             if (entity == null)
     232:             {
     233:                 throw new ArgumentNullException("entity");
     234:             }
     235:             DbContext.Set<TEntity>().Remove(entity);
     236:         }
     237:   
     238:         public void Delete<TEntity>(Expression<Func<TEntity,
     239:         bool>> criteria) where TEntity : class
     240:         {
     241:             IEnumerable<TEntity> records = Find(criteria);
     242:   
     243:             foreach (TEntity record in records)
     244:             {
     245:                 Delete(record);
     246:             }
     247:         }
     248:   
     249:         #endregion
     250:   
     251:         #region Internal Processing Private Methods
     252:   
     253:         private EntityKey GetEntityKey<TEntity>(object keyValue) where TEntity : class
     254:         {
     255:             string entitySetName = GetEntityName<TEntity>();
     256:             ObjectSet<TEntity> objectSet =
     257:             ((IObjectContextAdapter)DbContext).ObjectContext.CreateObjectSet<TEntity>();
     258:             string keyPropertyName = objectSet.EntitySet.ElementType.KeyMembers[0].ToString();
     259:             var entityKey = new EntityKey
     260:             (entitySetName, new[] { new EntityKeyMember(keyPropertyName, keyValue) });
     261:             return entityKey;
     262:         }
     263:   
     264:         private string GetEntityName<TEntity>() where TEntity : class
     265:         {
     266:             // Thanks to Kamyar Paykhan -
     267:             // http://huyrua.wordpress.com/2011/04/13/
     268:             // entity-framework-4-poco-repository-and-specification-pattern-upgraded-to-ef-4-1/
     269:             // #comment-688
     270:             string entitySetName = ((IObjectContextAdapter)DbContext).ObjectContext
     271:                 .MetadataWorkspace
     272:                 .GetEntityContainer(((IObjectContextAdapter)DbContext).
     273:                     ObjectContext.DefaultContainerName,
     274:                     DataSpace.CSpace)
     275:                 .BaseEntitySets.Where(bes => bes.ElementType.Name == typeof(TEntity).Name).First().Name;
     276:             return string.Format("{0}.{1}",
     277:             ((IObjectContextAdapter)DbContext).ObjectContext.DefaultContainerName,
     278:                 entitySetName);
     279:         }
     280:   
     281:         private string RemoveAccent(string txt)
     282:         {
     283:             byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(txt);
     284:             return System.Text.Encoding.ASCII.GetString(bytes);
     285:         }
     286:   
     287:         private bool IsValidTag(string tag, string tags)
     288:         {
     289:             string[] allowedTags = tags.Split(‘,‘);
     290:             if (tag.IndexOf("javascript") >= 0) return false;
     291:             if (tag.IndexOf("vbscript") >= 0) return false;
     292:             if (tag.IndexOf("onclick") >= 0) return false;
     293:   
     294:             var endchars = new char[] { ‘ ‘, ‘>‘, ‘/‘, ‘\t‘ };
     295:   
     296:             int pos = tag.IndexOfAny(endchars, 1);
     297:             if (pos > 0) tag = tag.Substring(0, pos);
     298:             if (tag[0] == ‘/‘) tag = tag.Substring(1);
     299:   
     300:             foreach (string aTag in allowedTags)
     301:             {
     302:                 if (tag == aTag) return true;
     303:             }
     304:   
     305:             return false;
     306:         }
     307:   
     308:         #endregion
     309:   
     310:         #region Disposing Methods
     311:   
     312:         protected void Dispose(bool bDisposing)
     313:         {
     314:             if (!bDisposed)
     315:             {
     316:                 if (bDisposing)
     317:                 {
     318:                     if (null != context)
     319:                     {
     320:                         context.Dispose();
     321:                     }
     322:                 }
     323:                 bDisposed = true;
     324:             }
     325:         }
     326:   
     327:         public void Close()
     328:         {
     329:             Dispose(true);
     330:             GC.SuppressFinalize(this);
     331:         }
     332:   
     333:         #endregion
     334:     }
  3. IUnitOfWork 接口
       1:      public interface IUnitOfWork : IDisposable
       2:      {
       3:          void SaveChanges();
       4:      }
  4. UnitOfWork 类
       1:      internal class UnitOfWork : IUnitOfWork
       2:      {
       3:          private readonly DbContext _dbContext;
       4:   
       5:          public UnitOfWork(DbContext context)
       6:          {
       7:              _dbContext = context;
       8:          }
       9:   
      10:          public void SaveChanges()
      11:          {
      12:              ((IObjectContextAdapter)_dbContext).ObjectContext.SaveChanges();
      13:          }
      14:   
      15:          #region Implementation of IDisposable
      16:   
      17:          private bool _disposed;
      18:   
      19:          /// <summary>
      20:          ///     Performs application-defined tasks associated with freeing, 
      21:          ///     releasing, or resetting unmanaged resources.
      22:          /// </summary>
      23:          public void Dispose()
      24:          {
      25:              Dispose(true);
      26:              GC.SuppressFinalize(this);
      27:          }
      28:   
      29:          /// <summary>
      30:          ///     Disposes off the managed and unmanaged resources used.
      31:          /// </summary>
      32:          /// <param name="disposing"></param>
      33:          private void Dispose(bool disposing)
      34:          {
      35:              if (!disposing)
      36:                  return;
      37:   
      38:              if (_disposed)
      39:                  return;
      40:   
      41:              _disposed = true;
      42:          }
      43:   
      44:          #endregion
      45:      }

在Mayur.DAL.Core文件夹中,还有一个抽象类,包含了一些项目中常用到的公共方法,如果你也有一些新的方法函数是我们在项目中需要的,请在评论中提出建议(原文这么说的,在我这评论我也不介意)。

  1. GlobalCommonHelper.cs 类

       1:   abstract public class GlobalCommonHelper
       2:      {
       3:          #region General Methods
       4:   
       5:          /// <summary>
       6:          /// Take any string and encrypt it using SHA1 then
       7:          /// return the encrypted data
       8:          /// </summary>
       9:          /// <param name="data">input text you will enterd to encrypt it</param>
      10:          /// <returns>return the encrypted text as hexadecimal string</returns>
      11:          public string GetSHA1HashData(string data)
      12:          {
      13:              //create new instance of md5
      14:              SHA1 sha1 = SHA1.Create();
      15:   
      16:              //convert the input text to array of bytes
      17:              byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data));
      18:   
      19:              //create new instance of StringBuilder to save hashed data
      20:              StringBuilder returnValue = new StringBuilder();
      21:   
      22:              //loop for each byte and add it to StringBuilder
      23:              for (int i = 0; i < hashData.Length; i++)
      24:              {
      25:                  returnValue.Append(hashData[i].ToString());
      26:              }
      27:   
      28:              // return hexadecimal string
      29:              return returnValue.ToString();
      30:          }
      31:   
      32:          /// <summary>
      33:          /// Creates a slug url from string .
      34:          /// </summary>
      35:          /// <param name="phrase"></param>
      36:          /// <returns></returns>
      37:          public string GetSlugURLFromString(string phrase)
      38:          {
      39:              string str = RemoveAccent(phrase).ToLower();
      40:              // invalid chars          
      41:              str = Regex.Replace(str, @"[^a-z0-9\s-]", "");
      42:              // convert multiple spaces into one space  
      43:              str = Regex.Replace(str, @"\s+", " ").Trim();
      44:              // cut and trim
      45:              str = str.Substring(0, str.Length <= 45 ? str.Length : 45).Trim();
      46:              str = Regex.Replace(str, @"\s", "-"); // hyphens  
      47:              return str;
      48:          }
      49:   
      50:          /// <summary>
      51:          /// Delete file by specified path.
      52:          /// </summary>
      53:          /// <param name="path">path of file.</param>
      54:          public void DeleteTargetFile(string path)
      55:          {
      56:              if (File.Exists(path))
      57:              {
      58:                  File.SetAttributes(path, FileAttributes.Normal);
      59:                  File.Delete(path);
      60:              }
      61:          }
      62:   
      63:          /// <summary>
      64:          /// Sent email to target email address with attachment.
      65:          /// </summary>
      66:          /// <param name="toEmail">Email addresses of 
      67:          /// one or multiple receipients semi colon (;) separated values.</param>
      68:          /// <param name="subject">Email subject</param>
      69:          /// <param name="body">Email body</param>
      70:          /// <returns>True | False</returns>
      71:          public bool SendEmailToTarget(string toEmail, string subject, string body)
      72:          {
      73:   
      74:              bool success = false;
      75:              try
      76:              {
      77:                  SmtpClient SmtpServer = new SmtpClient();
      78:                  MailMessage mail = new MailMessage();
      79:   
      80:                  SmtpServer.Credentials = new NetworkCredential(
      81:                      Convert.ToString(ConfigurationManager.AppSettings["fromEmail"]),
      82:                      Convert.ToString(ConfigurationManager.AppSettings["fromPassword"]));
      83:   
      84:                  SmtpServer.Host = Convert.ToString
      85:                  (ConfigurationManager.AppSettings["hostName"]);
      86:                  SmtpServer.Port = Convert.ToInt32
      87:                  (ConfigurationManager.AppSettings["portNumber"]);
      88:   
      89:                  if (Convert.ToBoolean
      90:                  (ConfigurationManager.AppSettings["isEnableSSL"]) == true)
      91:                      SmtpServer.EnableSsl = true;
      92:   
      93:                  mail.From = new MailAddress(Convert.ToString
      94:                  (ConfigurationManager.AppSettings["senderName"]));
      95:   
      96:                  string[] multiEmails = toEmail.Split(‘;‘);
      97:                  foreach (string email in multiEmails)
      98:                  {
      99:                      mail.To.Add(email);
     100:                  }
     101:   
     102:                  mail.Subject = subject;
     103:                  mail.IsBodyHtml = true;
     104:                  mail.Body = body;
     105:                  SmtpServer.Send(mail);
     106:                  mail.Dispose();
     107:                  success = true;
     108:              }
     109:              catch (Exception)
     110:              {
     111:                  success = false;
     112:              }
     113:              return success;
     114:          }
     115:   
     116:          /// <summary>
     117:          /// Sent email to target email address with attachment.
     118:          /// </summary>
     119:          /// <param name="toEmail">Email addresses of 
     120:          /// one or multiple receipients semi colon (;) separated values.</param>
     121:          /// <param name="subject">Email subject</param>
     122:          /// <param name="body">Email body</param>
     123:          /// <param name="body">Email attachment file path</param>
     124:          /// <returns>True | False</returns>
     125:          public bool SendEmailToTarget(string toEmail, string subject, string body, string attachmentPath)
     126:          {
     127:   
     128:              bool success = false;
     129:              try
     130:              {
     131:                  SmtpClient SmtpServer = new SmtpClient();
     132:                  MailMessage mail = new MailMessage();
     133:   
     134:                  SmtpServer.Credentials = new NetworkCredential(
     135:                      Convert.ToString(ConfigurationManager.AppSettings["fromEmail"]),
     136:                      Convert.ToString(ConfigurationManager.AppSettings["fromPassword"]));
     137:   
     138:                  SmtpServer.Host = Convert.ToString
     139:                  (ConfigurationManager.AppSettings["hostName"]);
     140:                  SmtpServer.Port = Convert.ToInt32
     141:                  (ConfigurationManager.AppSettings["portNumber"]);
     142:   
     143:                  if (Convert.ToBoolean(ConfigurationManager.AppSettings["isEnableSSL"]) == true)
     144:                      SmtpServer.EnableSsl = true;
     145:   
     146:                  mail.From = new MailAddress(Convert.ToString
     147:                  (ConfigurationManager.AppSettings["senderName"]));
     148:   
     149:                  string[] multiEmails = toEmail.Split(‘;‘);
     150:                  foreach (string email in multiEmails)
     151:                  {
     152:                      mail.To.Add(email);
     153:                  }
     154:   
     155:                  Attachment attachment;
     156:                  attachment = new System.Net.Mail.Attachment(attachmentPath);
     157:                  mail.Attachments.Add(attachment);
     158:   
     159:                  mail.Subject = subject;
     160:                  mail.IsBodyHtml = true;
     161:                  mail.Body = body;
     162:                  SmtpServer.Send(mail);
     163:                  mail.Dispose();
     164:                  success = true;
     165:              }
     166:              catch (Exception)
     167:              {
     168:                  success = false;
     169:              }
     170:              return success;
     171:          }
     172:   
     173:          /// <summary>
     174:          /// Strips tags
     175:          /// </summary>
     176:          /// <param name="text">Text</param>
     177:          /// <returns>Formatted text</returns>
     178:          public string RemoveHtmlFromString(string text)
     179:          {
     180:              if (String.IsNullOrEmpty(text))
     181:              {
     182:                  return string.Empty;
     183:              }
     184:              else{
     185:                  
     186:   
     187:              text = Regex.Replace(text, @"(>)(\r|\n)*(<)", "><");
     188:              text = Regex.Replace(text, "(<[^>]*>)([^<]*)", "$2");
     189:              text = Regex.Replace(text, "(&#x?[0-9]{2,4};||&| |<|>|&euro;|&copy;|&reg;|&permil;|&Dagger;|&dagger;|&lsaquo;|&rsaquo;|&bdquo;|&rdquo;|&ldquo;|&sbquo;|&rsquo;|&lsquo;|&mdash;|&ndash;|&rlm;|&lrm;|&zwj;|&zwnj;|&thinsp;|&emsp;|&ensp;|&tilde;|&circ;|&Yuml;|&scaron;|&Scaron;)", "@");
     190:              return text;
     191:  }
     192:          }
     193:   
     194:          /// <summary>
     195:          /// Verifies that a string is in valid e-mail format
     196:          /// </summary>
     197:          /// <param name="email">Email to verify</param>
     198:          /// <returns>true if the string is a valid e-mail address and false if it‘s not</returns>
     199:          public bool IsValidEmail(string email)
     200:          {
     201:              if (String.IsNullOrEmpty(email))
     202:                  return false;
     203:   
     204:              email = email.Trim();
     205:              var result = Regex.IsMatch(email, "^(?:[\\w\\!\\#\\$\\%\\&\\‘\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~]+\\.)*[\\w\\!\\#\\$\\%\\&\\‘\\*\\+\\-\\/\\=\\?\\^\\`\\{\\|\\}\\~][email protected](?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!\\.)){0,61}[a-zA-Z0-9]?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\\[(?:(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\.){3}(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\]))$", RegexOptions.IgnoreCase);
     206:              return result;
     207:          }
     208:   
     209:          /// <summary>
     210:          /// Returns Allowed HTML only.
     211:          /// </summary>
     212:          /// <param name="text">Text</param>
     213:          /// <returns>Allowed HTML</returns>
     214:          public string EnsureOnlyAllowedHtml(string text)
     215:          {
     216:              if (String.IsNullOrEmpty(text))
     217:                  return string.Empty;
     218:   
     219:              const string allowedTags = "br,hr,b,i,u,a,div,ol,ul,li,blockquote,img,span,p,em," +
     220:                                          "strong,font,pre,h1,h2,h3,h4,h5,h6,address,cite";
     221:   
     222:              var m = Regex.Matches(text, "<.*?>", RegexOptions.IgnoreCase);
     223:              for (int i = m.Count - 1; i >= 0; i--)
     224:              {
     225:                  string tag = text.Substring(m[i].Index + 1, m[i].Length - 1).Trim().ToLower();
     226:   
     227:                  if (!IsValidTag(tag, allowedTags))
     228:                  {
     229:                      text = text.Remove(m[i].Index, m[i].Length);
     230:                  }
     231:              }
     232:   
     233:              return text;
     234:          }
     235:   
     236:          #endregion
     237:   
     238:          #region Internal Processing Private Methods
     239:   
     240:          private string RemoveAccent(string txt)
     241:          {
     242:              byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(txt);
     243:              return System.Text.Encoding.ASCII.GetString(bytes);
     244:          }
     245:   
     246:          private bool IsValidTag(string tag, string tags)
     247:          {
     248:              string[] allowedTags = tags.Split(‘,‘);
     249:              if (tag.IndexOf("javascript") >= 0) return false;
     250:              if (tag.IndexOf("vbscript") >= 0) return false;
     251:              if (tag.IndexOf("onclick") >= 0) return false;
     252:   
     253:              var endchars = new char[] { ‘ ‘, ‘>‘, ‘/‘, ‘\t‘ };
     254:   
     255:              int pos = tag.IndexOfAny(endchars, 1);
     256:              if (pos > 0) tag = tag.Substring(0, pos);
     257:              if (tag[0] == ‘/‘) tag = tag.Substring(1);
     258:   
     259:              foreach (string aTag in allowedTags)
     260:              {
     261:                  if (tag == aTag) return true;
     262:              }
     263:   
     264:              return false;
     265:          }
     266:   
     267:          #endregion
     268:   
     269:      }

现在通用仓储已经具备了公共的方法,现在来看下我们怎么在控制器中使用它。假设我们有一个Student实体,包含studentID, name, rollNo 等列,下面是控制器中的代码

  1. 在继续之前,我们需要先完善数据上下文信息,以生成数据库和数据表 ,如下:

       1:      public class MyFirstDbContext:DbContext
       2:      {
       3:          public MyFirstDbContext()
       4:              : base("name=MyFirstDbContext")
       5:          {
       6:              Database.SetInitializer<MyFirstDbContext>(null);
       7:          }
       8:   
       9:          public virtual DbSet<Book> Books { get; set; }
      10:   
      11:          protected override void OnModelCreating(DbModelBuilder modelBuilder)
      12:          {
      13:   
      14:          }
      15:   
      16:      }
  2. 我在数据访问层创建了一个抽象的包含了每个项目中都要使用的公共方法的类。因为是一个抽象类,这意味着我们为它创建实例。所以我们需要创建一个新的类在Web项目中,这个类继承于GlobalCommonHelper类,命名为CommonHelper,我们可以在这个类中实现一些项目独有的公共方法。
       1:      public class CommonHelper : GlobalCommonHelper
       2:      {
       3:          public int PageSize = 25;
       4:          //Some common functions. Only Project-specific.     
       5:      }
  3. 现在我们可以看下如何在我们的控制器中使用仓储类,看控制器中的代码:
       1:  public class BooksController : Controller
       2:      {
       3:          private IRepository repository;
       4:          private CommonHelper helper;
       5:   
       6:          public BooksController()
       7:          {
       8:              repository=new Repository(new MyFirstDbContext());
       9:              helper=new CommonHelper();
      10:          }
      11:   
      12:          // GET: Books
      13:          public ActionResult Index()
      14:          {
      15:              var list = repository.GetAll<Book>();
      16:              return View(list);
      17:          }
      18:   
      19:          // GET: Books/Details/5
      20:          public ActionResult Details(int id=0)
      21:          {
      22:              if (id == 0)
      23:              {
      24:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      25:              }
      26:   
      27:              Book book = repository.FindOne<Book>(b => b.Id == id);
      28:              if (book == null)
      29:              {
      30:                  return HttpNotFound();
      31:              }
      32:              return View(book);
      33:          }
      34:   
      35:          // GET: Books/Create
      36:          public ActionResult Create()
      37:          {
      38:              return View();
      39:          }
      40:   
      41:          // POST: Books/Create
      42:          // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
      43:          // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
      44:          [HttpPost]
      45:          [ValidateAntiForgeryToken]
      46:          public ActionResult Create([Bind(Include = "Id,Cover,BookName,Author,TranslatedName,Translator,Publisher,WordCount,Pages,ISBN,Price,SalePrice,PublicationDate,Introduction,AboutTheAuthors,Link")] Book book)
      47:          {
      48:              if (ModelState.IsValid)
      49:              {
      50:                  repository.Add(book);
      51:                  repository.UnitOfWork.SaveChanges();
      52:                  
      53:                  return RedirectToAction("Index");
      54:              }
      55:   
      56:              return View(book);
      57:          }
      58:   
      59:          // GET: Books/Edit/5
      60:          public ActionResult Edit(int id=0)
      61:          {
      62:              if (id == 0)
      63:              {
      64:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      65:              }
      66:              Book book = repository.FindOne<Book>(x => x.Id == id);
      67:              if (book == null)
      68:              {
      69:                  return HttpNotFound();
      70:              }
      71:              return View(book);
      72:          }
      73:   
      74:          // POST: Books/Edit/5
      75:          // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
      76:          // 详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=317598。
      77:          [HttpPost]
      78:          [ValidateAntiForgeryToken]
      79:          public ActionResult Edit([Bind(Include = "Id,Cover,BookName,Author,TranslatedName,Translator,Publisher,WordCount,Pages,ISBN,Price,SalePrice,PublicationDate,Introduction,AboutTheAuthors,Link")] Book book)
      80:          {
      81:              if (ModelState.IsValid)
      82:              {
      83:                  repository.Update<Book>(book);
      84:                  repository.UnitOfWork.SaveChanges();
      85:                  //db.Entry(book).State = EntityState.Modified;
      86:                  //db.SaveChanges();
      87:                  return RedirectToAction("Index");
      88:              }
      89:              return View(book);
      90:          }
      91:   
      92:          // GET: Books/Delete/5
      93:          public ActionResult Delete(int id=0)
      94:          {
      95:              if (id == 0)
      96:              {
      97:                  return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      98:              }
      99:              Book book = repository.FindOne<Book>(b => b.Id == id);
     100:              if (book == null)
     101:              {
     102:                  return HttpNotFound();
     103:              }
     104:              return View(book);
     105:          }
     106:   
     107:          // POST: Books/Delete/5
     108:          [HttpPost, ActionName("Delete")]
     109:          [ValidateAntiForgeryToken]
     110:          public ActionResult DeleteConfirmed(int id)
     111:          {
     112:              Book book = repository.FindOne<Book>(b => b.Id == id);
     113:              if (book == null)
     114:              {
     115:                  return HttpNotFound();
     116:              }
     117:              repository.Delete<Book>(book);
     118:              repository.UnitOfWork.SaveChanges();
     119:              //db.Books.Remove(book);
     120:              //db.SaveChanges();
     121:              return RedirectToAction("Index");
     122:          }
     123:        
     124:      }

我需要更多来自你的建议和改进,请提给我吧。(原作)

译注

正好在学习仓储模式和工作单元,想整理一个通用的仓储类,作者的做参考。

英语不好有些翻译很生硬,还有的直接表意,省掉了作者一些话(他们写文章都很认真,像教小学生一样敦敦教诲)

版本

•31/05/2015: Article published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

转载自:http://www.cnblogs.com/wit13142/p/5435368.html

时间: 2024-10-06 23:04:52

(译文)MVC通用仓储类的相关文章

DbContext通用数据仓储类

/// <summary> /// 数据仓储类 /// </summary> /// <typeparam name="T">实体模型</typeparam> public class Repository<T> where T : class { /// <summary> /// 数据上下文 /// </summary> public DbContext DbContext { get; set;

细说MVC中仓储模式的应用

文章提纲 概述要点 理论基础 详细步骤 总结 概述要点 设计模式的产生,就是在对开发过程进行不断的抽象. 我们先看一下之前访问数据的典型过程. 在Controller中定义一个Context, 例如: private AccountContext db = new AccountContext(); 在Action中访问,例如获取用户列表: var users=db.SysUsers; 类似于这种,耦合性太高.业务逻辑直接访问数据存储层会导致一些问题,如 重复代码:不容易集中使用数据相关策略,例

第一篇:无角牛MVC通用后台数据库设计

v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:url(#default#VML);} .shape {behavior:url(#default#VML);} Normal 0 false 7.8 磅 0 2 false false false EN-US ZH-CN X-NONE /* Style Definitions */ table.MsoNormalTable {

自制MVC之工具类插件一

1).BreakRomoteURLAttribute 提交或交互的URL数据是否来源于其它地方,站内提交,防止跨站 2). DataAttribute 取得post或get提交的数据.如果没有特殊设置,取得的数据是sql注入.xss注入过滤的. 属性名 作用 默认值 选项说明 其它说明 IsEmpty 是否可以提交空数据,就是表单数值一个都没有的情况. true 必填 AspectPriority 插件执行优先级 空 可选 MD5Key 需md5加密的key,多个用逗号分隔. 10000 可选

C#数据仓储类

https://ninesky.codeplex.com/SourceControl/latest 1 /*============================== 2 版本:v0.1 3 创建:2016.2.6 4 作者:洞庭夕照 5 博客:http://mzwhj.cnblogs.com 6 ----------------------------- 7 修改:2016.3.4 8 public int Delete(T entity, bool isSave) 9 Remove 改为A

[.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) JSON序列化利器 Newtonsoft.Json 及 通用Json类

[.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) JSON序列化利器 Newtonsoft.Json 及 通用Json类 本节导读: 关于JSON序列化,不能不了解Json.net(Newtonsoft.Json)这款世界级的开源类库,除了拥有良好的性能之外,功能也是非常强大的. 本节会详细说明这个类库.此外,对于不喜欢使用第三方类库的同学,会整理一个基于微软类库的通用Json类. 读前必备: 本节主要介绍一款第三方类库和一个自己整理封装的类库,说起到封装

C#:数据库通用访问类 SqlHelper

using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using System.Globalization; using System.IO; using System.Text.RegularExpressions; using System.Xml; using System.Reflection;

Hibernate 通用DAO类

1.通用接口类 package org.lzpeng.dao; import java.io.Serializable; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.criterion.Criterion; import org.springside.modules.orm.hibernate.Page; /**  *   * @ver

通用窗口类 Inventory Pro 2.1.2 Demo1(下续篇 ),物品消耗扇形显示功能

本篇想总结的是Inventory Pro中通用窗口的具体实现,但还是要强调下该插件的重点还是装备系统而不是通用窗口系统,所以这里提到的通用窗口类其实是通用装备窗口类(其实该插件中也有非装备窗口比如NoticeUI等). 本篇涉及的功能用加出标出,具体的功能如下: 1.实现了两个窗口,通过点击键盘I来,打开或者关闭窗口也就是Toggle功能 2.装备窗口中的物品栏空格数量动态生成可控,可以在属性窗口手动配置 3.窗口具有拖拽功能 4.窗口物品具有拖拽,及窗口间拖拽 5.可以在窗口使用物品的功能,物