chsakell分享了一个前端使用AngularJS,后端使用ASP.NET Web API的项目。
源码: https://github.com/chsakell/spa-webapi-angularjs
文章:
这里记录下对此项目的理解。分为如下几篇:
● 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(1)--领域、Repository、Service
● 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(2)--依赖倒置、Bundling、视图模型验证、视图模型和领域模型映射、自定义handler
● 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(3)--主页面布局
● 对一个前端使用AngularJS后端使用ASP.NET Web API项目的理解(4)--Movie增改查以及上传图片
从数据库开始,项目架构大致为:
→SQL Server Database
→Domain Entities(放在了HomeCinema.Entities类库中)
→Generic Repositories(放在了HomeCinema.Data类库中,EF上下文、数据库迁移等放在了这里)
→Service Layer(与会员验证有关,放在了HomeCinema.Services类库中)
→Web API Controllers(放在了HomeCinema.Web的MVC的Web项目中,即ASP.NET Web API寄宿在ASP.NET MVC下)
→前端使用AngularJS
领域
所有的领域都有主键,抽象出一个接口,包含一个主键属性。
namespace HomeCinema.Entities { public interface IEntityBase { int ID { get; set; } } }
Genre和Moive,是1对多关系。
namespace HomeCinema.Entities { public class Genre : IEntityBase { public Genre() { Movies = new List<Movie>(); } public int ID { get; set; } public virtual ICollection<Movie> Movies { get; set; } } } namespace HomeCinema.Entities { public class Movie : IEntityBase { public Movie() { Stocks = new List<Stock>(); } public int ID { get; set; } //一个主键+一个导航属性,,标配 public int GenreId { get; set; } public virtual Genre Genre { get; set; } public virtual ICollection<Stock> Stocks { get; set; } } } Movie和Stock也是1对多关系。 namespace HomeCinema.Entities { public class Stock : IEntityBase { public Stock() { Rentals = new List<Rental>(); } public int ID { get; set; } public int MovieId { get; set; } public virtual Movie Movie { get; set; } public virtual ICollection<Rental> Rentals { get; set; } } }
Stock和Rental也是1对多关系。
namespace HomeCinema.Entities { public class Rental : IEntityBase { public int ID { get; set; } public int StockId { get; set; } public virtual Stock Stock { get; set; } } }
User和Role是多对多关系,用到了中间表UserRole。
namespace HomeCinema.Entities { public class User : IEntityBase { public User() { UserRoles = new List<UserRole>(); } public int ID { get; set; } public virtual ICollection<UserRole> UserRoles { get; set; } } } namespace HomeCinema.Entities { public class Role : IEntityBase { public int ID { get; set; } public string Name { get; set; } } } namespace HomeCinema.Entities { public class UserRole : IEntityBase { public int ID { get; set; } public int UserId { get; set; } public int RoleId { get; set; } public virtual Role Role { get; set; } } }
HomeCinema.Entities类库中的Customer和Error类是单独的,和其它类没有啥关系。
Repository
首先需要一个上下文类,继承DbContext,在构造函数中注明连接字符串的名称,生成数据库的方式等,提供某个领域的IDbSet<T>以便外界获取,提供单元提交的方法,以及提供一个方法使有关领域的配置生效。
namespace HomeCinema.Data { public class HomeCinemaContext : DbContext { public HomeCinemaContext() : base("HomeCinema") { Database.SetInitializer<HomeCinemaContext>(null); } #region Entity Sets public IDbSet<User> UserSet { get; set; } ... #endregion public virtual void Commit() { base.SaveChanges(); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Configurations.Add(new UserConfiguration()); ... } } }
以上的UserConfiguration继承于EntityBaseConfiguration<User>,而Configurations是EntityBaseConfiguration<T>的一个集合。