文章目录
概述
NopCommerce源码架构详解-EF相关Fluent API实现源码分析1。
内容
今天继续来写NopCommerce源码架构详解相关的文章,我们都知道nop中使用的是ORM框架是EF,并且是EF中的Fluent API形式。下面我就来分析一下里面的核心类及其实现原理。
1、实体相关的基础类
项目:Nop.Core
实体的抽象类BaseEntity
using System; namespace Nop.Core { /// <summary> /// 所有entities的基类 /// </summary> public abstract partial class BaseEntity { /// <summary> /// Id为实体的主键 /// </summary> public int Id { get; set; } public override bool Equals(object obj) { return Equals(obj as BaseEntity); } private static bool IsTransient(BaseEntity obj) { return obj != null && Equals(obj.Id, default(int)); } private Type GetUnproxiedType() { return GetType(); } public virtual bool Equals(BaseEntity other) { if (other == null) return false; if (ReferenceEquals(this, other)) return true; if (!IsTransient(this) && !IsTransient(other) && Equals(Id, other.Id)) { var otherType = other.GetUnproxiedType(); var thisType = GetUnproxiedType(); return thisType.IsAssignableFrom(otherType) || otherType.IsAssignableFrom(thisType); } return false; } public override int GetHashCode() { if (Equals(Id, default(int))) return base.GetHashCode(); return Id.GetHashCode(); } public static bool operator ==(BaseEntity x, BaseEntity y) { return Equals(x, y);//运算符的重载 } public static bool operator !=(BaseEntity x, BaseEntity y) { return !(x == y); } } }
项目Nop.Data
使用EF的泛型Repository类EfRepository,里面封装了一些公共的数据操作方法。
using System; using System.Data.Entity; using System.Data.Entity.Validation; using System.linq; using Nop.Core; using Nop.Core.Data; namespace Nop.Data { /// <summary> /// Entity Framework repository /// </summary> public partial class EfRepository<T> : IRepository<T> where T : BaseEntity { private readonly IDbContext _context; private IDbSet<T> _entities; /// <summary> /// Ctor /// </summary> /// <param name="context">Object context</param> public EfRepository(IDbContext context) { this._context = context; } /// <summary> /// Get entity by identifier /// </summary> /// <param name="id">Identifier</param> /// <returns>Entity</returns> public virtual T GetById(object id) { return this.Entities.Find(id); } /// <summary> /// 插入一个entity /// </summary> /// <param name="entity">Entity</param> public virtual void Insert(T entity) { try { if (entity == null) throw new ArgumentNullException("entity"); this.Entities.Add(entity); this._context.SaveChanges(); } catch (DbEntityValidationException dbEx) { var msg = string.Empty; foreach (var validationErrors in dbEx.EntityValidationErrors) foreach (var validationError in validationErrors.ValidationErrors) msg += string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage) + Environment.NewLine; var fail = new Exception(msg, dbEx); //Debug.WriteLine(fail.Message, fail); throw fail; } } /// <summary> /// 更新一个entity /// </summary> /// <param name="entity">Entity</param> public virtual void Update(T entity) { try { if (entity == null) throw new ArgumentNullException("entity"); this._context.SaveChanges(); } catch (DbEntityValidationException dbEx) { var msg = string.Empty; foreach (var validationErrors in dbEx.EntityValidationErrors) foreach (var validationError in validationErrors.ValidationErrors) msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); var fail = new Exception(msg, dbEx); //Debug.WriteLine(fail.Message, fail); throw fail; } } /// <summary> /// 删除一个 entity /// </summary> /// <param name="entity">Entity</param> public virtual void Delete(T entity) { try { if (entity == null) throw new ArgumentNullException("entity"); this.Entities.Remove(entity); this._context.SaveChanges(); } catch (DbEntityValidationException dbEx) { var msg = string.Empty; foreach (var validationErrors in dbEx.EntityValidationErrors) foreach (var validationError in validationErrors.ValidationErrors) msg += Environment.NewLine + string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage); var fail = new Exception(msg, dbEx); //Debug.WriteLine(fail.Message, fail); throw fail; } } /// <summary> /// 返回实体的集合 /// </summary> public virtual IQueryable<T> Table { get { return this.Entities; } } /// <summary> /// 采用no tracking的方式返回实体的集合,在只读情况下性能更好 /// </summary> public virtual IQueryable<T> TableNoTracking { get { return this.Entities.AsNoTracking(); } } /// <summary> /// Entities /// </summary> protected virtual IDbSet<T> Entities { get { if (_entities == null) _entities = _context.Set<T>(); return _entities; } } } }
2、映射实现Mapping

Nop的实体映射到数据库是通过继承基类EntityTypeConfiguration,手动配置映射关系。博客类BlogPost和评论BlogComment是通过下面方式实现的:
BlogPost.cs
using System; using System.Collections.Generic; using Nop.Core.Domain.Localization; using Nop.Core.Domain.seo; using Nop.Core.Domain.Stores; namespace Nop.Core.Domain.Blogs { /// <summary> /// Represents a blog post /// </summary> public partial class BlogPost : BaseEntity, ISlugSupported, IStoreMappingSupported { private ICollection<BlogComment> _blogComments; /// <summary> /// Gets or sets the language identifier /// </summary> public int LanguageId { get; set; } /// <summary> /// Gets or sets the blog post title /// </summary> public string Title { get; set; } /// <summary> /// Gets or sets the blog post title /// </summary> public string Body { get; set; } /// <summary> /// Gets or sets a value indicating whether the blog post comments are allowed /// </summary> public bool AllowComments { get; set; } /// <summary> /// Gets or sets the total number of comments /// <remarks> /// We use this property for performance optimization (no SQL command executed) /// </remarks> /// </summary> public int CommentCount { get; set; } /// <summary> /// Gets or sets the blog tags /// </summary> public string Tags { get; set; } /// <summary> /// Gets or sets the blog post start date and time /// </summary> public DateTime? StartDateUtc { get; set; } /// <summary> /// Gets or sets the blog post end date and time /// </summary> public DateTime? EndDateUtc { get; set; } /// <summary> /// Gets or sets the meta keywords /// </summary> public string MetaKeywords { get; set; } /// <summary> /// Gets or sets the meta description /// </summary> public string MetaDescription { get; set; } /// <summary> /// Gets or sets the meta title /// </summary> public string MetaTitle { get; set; } /// <summary> /// Gets or sets a value indicating whether the entity is limited/restricted to certain stores /// </summary> public virtual bool LimitedToStores { get; set; } /// <summary> /// Gets or sets the date and time of entity creation /// </summary> public DateTime CreatedOnUtc { get; set; } /// <summary> /// Gets or sets the blog comments /// </summary> public virtual ICollection<BlogComment> BlogComments { get { return _blogComments ?? (_blogComments = new List<BlogComment>()); } protected set { _blogComments = value; } } /// <summary> /// Gets or sets the language /// </summary> public virtual Language Language { get; set; } } }
BlogComment.cs
using System; using Nop.Core.Domain.Customers; namespace Nop.Core.Domain.Blogs { /// <summary> /// Represents a blog comment /// </summary> public partial class BlogComment : BaseEntity { /// <summary> /// Gets or sets the customer identifier /// </summary> public int CustomerId { get; set; } /// <summary> /// Gets or sets the comment text /// </summary> public string CommentText { get; set; } /// <summary> /// Gets or sets the blog post identifier /// </summary> public int BlogPostId { get; set; } /// <summary> /// Gets or sets the date and time of instance creation /// </summary> public DateTime CreatedOnUtc { get; set; } /// <summary> /// Gets or sets the customer /// </summary> public virtual Customer Customer { get; set; } /// <summary> /// Gets or sets the blog post /// </summary> public virtual BlogPost BlogPost { get; set; } } }
BlogPost和BlogComment一对多的关系配置。
BlogCommentMap.cs
using System.Data.Entity.ModelConfiguration; using Nop.Core.Domain.Blogs; namespace Nop.Data.Mapping.Blogs { public partial class BlogCommentMap : EntityTypeConfiguration<BlogComment> { public BlogCommentMap() { this.ToTable("BlogComment"); this.HasKey(pr => pr.Id); this.HasRequired(bc => bc.BlogPost) .WithMany(bp => bp.BlogComments) .HasForeignKey(bc => bc.BlogPostId); this.HasRequired(cc => cc.Customer) .WithMany() .HasForeignKey(cc => cc.CustomerId); } } }