《在ASP.NET Core中使用Apworks快速开发数据服务》一文中,我介绍了如何使用Apworks框架的数据服务来快速构建用于查询和管理数据模型的RESTful API,经过该文的介绍,你会看到,使用Apworks框架开发数据服务是何等简单快捷,提供的功能也很是多,好比对Hypermedia的支持,以及提供丰富的异常信息和调用栈信息。另外,Apworks数据服务能够支持各类类型的仓储(Repository)实现,在该文的案例中,我使用了MongoDB做为仓储的实现,这是为了快速方便地演示数据服务的搭建过程。若是你所使用的是关系型数据库,也没有关系(意思是没关系,不是说数据没有关系。。。-_-!!!),基于Entity Framework Core的仓储实现可以知足你的需求。html
在之前老版本的Apworks中,仓储的接口是支持饥饿加载的,也就是说,在延迟加载被启用的时候,仓储容许经过显式指定一系列的对象属性,当主对象被返回时,这些属性所指向的子对象也会同时返回。这样的设计在当时的场景下是合理的,由于是否须要加载某些属性是能够在程序中指定的,对于相似MongoDB的仓储实现,它没有延迟加载的概念,所以能够忽略这个参数。在Apworks数据服务中,因为仓储的操做会直接被DataServiceController调用,而相关的查询条件都是来自于RESTful API的,所以,很难在API的层面来肯定某些聚合的对象属性是否须要饥饿加载(Eager Loading)。另外一方面,禁用延迟加载又会产生性能问题,所以,在当前版本的实现中,我尚未考虑好用何种方式来解决这个问题。或许能够经过HTTP Header来指定须要饥饿加载的属性路径,但这是另外一个问题。总之,在接下来的案例中,你将看到,虽然数据已经添加成功,但在返回的结果里,被聚合的子对象将没法返回。我会设法解决这个问题。git
假设咱们须要使用Entity Framework快速构建一个支持增删改查操做的数据服务(Data Service),并但愿该服务可以在容器中运行,咱们能够首先新建一个ASP.NET Core的应用程序,而后依照下面的步骤进行:github
public class Address { public Guid Id { get; set; } public string Country { get; set; } public string State { get; set; } public string City { get; set; } public string Street { get; set; } public string ZipCode { get; set; } } public class Customer : IAggregateRoot<Guid> { public Guid Id { get; set; } public string Name { get; set; } public string Email { get; set; } public Address ContactAddress { get; set; } }
public class CustomerDbContext : DbContext { public DbSet<Customer> Customers { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Customer>() .ToTable("Customers") .HasKey(x => x.Id); modelBuilder.Entity<Customer>() .Property(x => x.Id) .ForSqlServerHasDefaultValueSql("newid()"); modelBuilder.Entity<Customer>() .Property(x => x.Name) .IsUnicode() .IsRequired() .HasMaxLength(20); modelBuilder.Entity<Customer>() .Property(x => x.Email) .IsUnicode() .IsRequired() .HasMaxLength(50); modelBuilder.Entity<Address>() .ToTable("Addresses") .HasKey(x => x.Id); modelBuilder.Entity<Address>() .Property(x => x.Id) .ForSqlServerHasDefaultValueSql("newid()"); base.OnModelCreating(modelBuilder); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=localhost\sqlexpress; Database=CustomerService; Integrated Security=SSPI;"); } }
Add-Migration InitialCreate Update-Database成功完成这一步骤后,咱们的数据库就已经准备好了。事实上,以上步骤都是开发一个Entity Framework Core应用程序所必须经历的标准步骤,目前尚未用到Apworks的功能(固然,将Customer定义成聚合根除外)。接下来,咱们开始实现并配置Apworks数据服务,接下来的步骤跟基于MongoDB的实现很是相似。
public class CustomersController : DataServiceController<Guid, Customer> { public CustomersController(IRepositoryContext repositoryContext) : base(repositoryContext) { } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); services.AddScoped<CustomerDbContext>(); services.AddApworks() .WithDataServiceSupport(new DataServiceConfigurationOptions(sp => new EntityFrameworkRepositoryContext(sp.GetService<CustomerDbContext>()))) .Configure(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.EnrichDataServiceExceptionResponse(); app.UseMvc(); }
下面,咱们来测试一下这个Apworks数据服务。在Visual Studio 2017中按下Ctrl+F5,直接运行ASP.NET Core应用程序,使用你喜欢的RESTful客户端软件,向/api/Customers进行POST操做,能够看到,Customer能够被成功建立,Customer Id即刻返回:sql
让咱们再GET一下试试(注意:返回的ContactAddress是null,而事实上数据库里是有值的。这里返回null的缘由是由于咱们没有在Entity Framework中经过Include调用进行饥饿加载(Eager Loading),接下来会尝试解决这个问题):数据库
除了ContactAddress在GET请求中返回为null以外,其它各类行为,包括数据服务所支持的API接口、调用方式等,都与以前MongoDB的实现彻底相同。express
本文案例中的源代码能够在Apworks Examples开源项目中找到。本案例的源代码在Apworks.Examples.CustomerService.EntityFramework目录下。编程
本文带领着你们一块儿预览了Apworks数据服务对Entity Framework Core的支持,使得Apworks数据服务不只可使用MongoDB等NoSQL存储方案,也可使用关系型数据库存储方案,并且编程体验也是几乎相同的。这对于不一样应用场景下微服务的实现是很是有帮助的。虽然在Entity Framework Core的实现中,目前有些瑕疵,但我会尽快解决这个问题。api