在本网站中,我们允许用户不用注册而直接将书籍放入购物车,直到下订单时才需要在网站中注册。因此购物逻辑与下订单逻辑分为两个控制器来进行处理:一个购 物控制器允许匿名用户将书籍放入购物车中,一个下订单控制器用来处理下订单的过程。在本节中,我们介绍购物控制器,在下一节中介绍下订单控制器。
8.1 追加购物车、订单与订单细节模型类
购物逻辑与下订单逻辑将要使用到一些新的模型类。鼠标右击Models文件夹,追加一个Cart(购物车)类(Cart.cs文件),并且写入代码清单8-1中所示的代码。
代码清单8-1 购物车类中的代码
using System.ComponentModel.DataAnnotations;
namespace MvcBookStore.Models
{
public class Cart
{
[Key]
public int RecordId { get; set; }
public string CartId { get; set; }
public int BookId { get; set; }
public int Count { get; set; }
public System.DateTime DateCreated { get; set; }
public virtual Book Book { get; set; }
}
}
这个类与之前我们创建的几个模型类非常类似,除了RecordId属性中使用了[Key]属性。我们的每一条购物车数据中将有一个唯一的字符串属性 CartID,依靠它来允许匿名用户购买书籍,但是Cart数据表中使用一个整型主键RecordId。从惯例上来说,Entity Framework Code-First希望Cart表的主键应该是CartId或者ID属性。但是我们可以通过注解或代码来不执行这个惯例。可以通过本教程的示例来看出当 我们需要的时候可以使用Entity Framework Code-First中使用的简单惯例,但是在不需要的时候如何不执行这个惯例。
使用如下所示的代码在数据库中添加Carts表。
CREATE TABLE [dbo].[Carts](
[RecordId] [int] IDENTITY(1,1) NOT NULL,
[CartId] [varchar](50) NOT NULL,
[BookId] [int] NOT NULL,
[Count] [int] NOT NULL,
[DateCreated] [datetime] NOT NULL,
CONSTRAINT [PK_Cart] PRIMARY KEY CLUSTERED
(
[RecordId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Carts] WITH CHECK ADD CONSTRAINT [FK_Cart_Book] FOREIGN
KEY([BookId])
REFERENCES [dbo].[Books] ([Id])
GO
ALTER TABLE [dbo].[Carts] CHECK CONSTRAINT [FK_Cart_Book]
GO
接下来,添加Order类(Order.cs文件),代码如代码清单8-2所示。
代码清单8-2 订单类中的代码
using System.Collections.Generic;
namespace MvcBookStore.Models
{
public partial class Order
{
public int OrderId { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public decimal Total { get; set; }
public System.DateTime OrderDate { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
}
}
使用这个类来记录用户的购物摘要信息与送货信息。如果现在编译不成功的话,是因为它还使用了一个OrderDetails(订单细节)属性,该属性还依赖于一个我们还没有创建的类。
使用如代码清单8-3中所示代码创建订单细节类(OrderDetail.cs文件)。
代码清单8-3 订单细节类中的代码
namespace MvcBookStore.Models
{
public class OrderDetail
{
public int OrderDetailId { get; set; }
public int OrderId { get; set; }
public int BookId { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public virtual Book Book { get; set; }
public virtual Order Order { get; set; }
}
}
使用如下所示的代码在数据库中添加Orders表与OrderDetails表。
CREATE TABLE [dbo].[Orders](
[OrderId] [int] IDENTITY(1,1) NOT NULL,
[OrderDate] [datetime] NOT NULL,
[Username] [nvarchar](256) NULL,
[FirstName] [nvarchar](160) NULL,
[LastName] [nvarchar](160) NULL,
[Address] [nvarchar](70) NULL,
[City] [nvarchar](40) NULL,
[State] [nvarchar](40) NULL,
[PostalCode] [nvarchar](10) NULL,
[Country] [nvarchar](40) NULL,
[Phone] [nvarchar](24) NULL,
[Email] [nvarchar](160) NULL,
[Total] [numeric](10, 2) NOT NULL,
CONSTRAINT [PK__Invoice__D796AAB51A14E395] PRIMARY KEY CLUSTERED
(
[OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[OrderDetails](
[OrderDetailId] [int] IDENTITY(1,1) NOT NULL,
[OrderId] [int] NOT NULL,
[BookId] [int] NOT NULL,
[Quantity] [int] NOT NULL,
[UnitPrice] [numeric](10, 2) NOT NULL,
CONSTRAINT [PK__InvoiceL__0D760AD91DE57479] PRIMARY KEY CLUSTERED
(
[OrderDetailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IFK_Invoice_InvoiceLine] ON [dbo].[OrderDetails]
(
[OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IPK_InvoiceLine] ON [dbo].[OrderDetails]
(
[OrderDetailId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[OrderDetails] WITH CHECK ADD
CONSTRAINT [FK__InvoiceLi__Invoi__2F10007B] FOREIGN KEY([OrderId])
REFERENCES [dbo].[Orders] ([OrderId])
GO
ALTER TABLE [dbo].[OrderDetails] CHECK
CONSTRAINT [FK__InvoiceLi__Invoi__2F10007B]
GO
ALTER TABLE [dbo].[OrderDetails] WITH CHECK ADD
CONSTRAINT [FK_InvoiceLine_Books] FOREIGN KEY([BookId])
REFERENCES [dbo].[Books] ([Id])
GO
最后,我们将修改BookStoreEntities类中的代码,添加新增模型类的DbSet集合。代码如代码清单8-4所示。
代码清单8-4 修改后的BookStoreEntities类中的代码
using System.Data.Entity;
namespace MvcBookStore.Models
{
public class BookStoreEntities : DbContext
{
public DbSet<Book> Books { get; set; }
public DbSet<Genre> Genres { get; set; }
public DbSet<Author> Authors { get; set; }
public DbSet<Cart> Carts { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
}
}