ASP.NET MVC Music Store教程(8):购物车和AJAX更新

转自 http://firechun.blog.163.com/blog/static/3180452220110314454425/

我们允许用户在没注册的情况下把唱片放进他们的购物车,但是当他们要结算时就必须注册为会员。购物和结算将使用两个不同的控制 器:ShoppingCartController允许匿名用户把商品放进购物车,CheckoutController则处理结算过程。这一章我们从购 物车开始,下一章我们创建结算。
添加Cart、Order和OrderDetails模型类

购物和结算都要使用某些新的类,在Models文件夹上单击右键添加Cart类(Card.cs),代码如下:

using System.ComponentModel.DataAnnotations; 
  
namespace MvcMusicStore.Models 

    public class Cart 
    { 
        [Key] 
        public int      RecordId    { get; set; } 
        public string   CartId      { get; set; } 
        public int      AlbumId     { get; set; } 
        public int      Count       { get; set; } 
        public System.DateTime DateCreated { get; set; } 
        public virtual Album Album  { get; set; } 
    } 
}

除 了RecordId属性的[KEY]特性外,这个类与目前我们使用的其它类非常相似。Cart有一个叫CartId的字符串标识,以便允许匿名者购物,但 是RecordId是表的整形主键。习惯上,实体框架“代码优先”会认为Cart表的主键是CartId或ID,而如果需要的话,我们很容易通过注释或代 码忽略这一点。上面就是一个例子,当实体框架“代码优先”的约定适合我们时,我们就使用,反之,我们也不会被这些约定限制。

接下来添中Order类(Order.cs):

using System.Collections.Generic; 
  
namespace MvcMusicStore.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导航属性依赖的类我们还没创建,让我们添加一个OrderDetails类(OrderDetails.cs):

namespace MvcMusicStore.Models 

    public class OrderDetail 
    { 
        public int OrderDetailId { get; set; } 
        public int OrderId { get; set; } 
        public int AlbumId { get; set; } 
        public int Quantity { get; set; } 
        public decimal UnitPrice { get; set; } 
        public virtual Album Album { get; set; } 
        public virtual Order Order { get; set; } 
    } 
}

现在做最后一个更新,在MusicStoreEntities类中添加这些新模型类的DbSet,更新后的MusicStoreEntities类如下:

using System.Data.Entity; 
  
namespace MvcMusicStore.Models 

    public class MusicStoreEntities : DbContext 
    { 
        public DbSet<Album>     Albums  { get; set; } 
        public DbSet<Genre>     Genres  { get; set; } 
        public DbSet<Artist>    Artists { get; set; } 
        public DbSet<Cart>      Carts { get; set; } 
        public DbSet<Order>     Orders { get; set; } 
        public DbSet<OrderDetail> OrderDetails { get; set; } 
    } 
}

管理购物车的业务逻辑

下面我们在Models文件夹中创建一个ShoppingCart类,ShoppingCart模型处理对Cart表的数据访问,并且还处理往购物车添加和移除商品的业务逻辑。

我们不想让用户仅仅为了往购物车内放一个商品就去申请帐号,当他们访问购物车时,我们给他们分配一个临时的唯一标识(使用GUID,全球唯一标识符),使用ASP.NET的Session来保存这个ID。

注: ASP.NET Session 能够方便地保存用户特定信息,并且在用户离开网站后自动过期。虽然滥用Sission会对较大站点产生影响,为了演示目的的轻量级使用没有任何问题。

ShoppingCart类公开以下方法:

AddToCart:以一个Album对象为参数,并把它添加到用户的购物车中。因为Cart表记录每种唱片的数量,方法中包括在需要时创建一个新行或者当用户拿取已有的唱片时增加该唱片的数量的业务逻辑。

RemoveFromCart:以Album ID为参数,并从用户的购物车中把它移除。如果用户的购物车中该唱片只有一份,则删除一行。

EmptyCart:从用户的购物车中移除所有商品

GetCartItems:返回购物车中的商品列表

GetCount:返回用户购物车中的唱片的总数

GetTotal:计算用户购物车中商品的总金额

CreateOrder:在结算阶段从购物车生成一张订单

GetCart:这是一个静态方法,允许控制器获得一个Cart对象。它调用GetCartId方法从用户的Session中读取CartId。GetCartId需要HttpContextBase以从用户的Sission中读取CartId。

下面是完整的ShoppingCart类的代码:

using System; 
 using System.Collections.Generic; 
 using System.Linq; 
 using System.Web; 
 using System.Web.Mvc; 
  
namespace MvcMusicStore.Models 

    public partial class ShoppingCart 
    { 
        MusicStoreEntities storeDB = new MusicStoreEntities(); 
        string ShoppingCartId { get; set; } 
        public const string CartSessionKey = "CartId"; 
        public static ShoppingCart GetCart(HttpContextBase context) 
        { 
            var cart = new ShoppingCart(); 
            cart.ShoppingCartId = cart.GetCartId(context); 
            return cart; 
        } 
        // Helper method to simplify shopping cart calls 
        public static ShoppingCart GetCart(Controller controller) 
        { 
            return GetCart(controller.HttpContext); 
        } 
        public void AddToCart(Album album) 
        { 
            // Get the matching cart and album instances 
            var cartItem = storeDB.Carts.SingleOrDefault( 
c => c.CartId == ShoppingCartId  
&& c.AlbumId == album.AlbumId); 
  
            if (cartItem == null) 
            { 
                // Create a new cart item if no cart item exists 
                cartItem = new Cart 
                { 
                    AlbumId = album.AlbumId, 
                    CartId = ShoppingCartId, 
                    Count = 1, 
                    DateCreated = DateTime.Now 
                }; 
                storeDB.Carts.Add(cartItem); 
            } 
            else 
            { 
                // If the item does exist in the cart, then add one to the 
quantity 
                cartItem.Count++; 
            } 
            // Save changes 
            storeDB.SaveChanges(); 
        } 
        public int RemoveFromCart(int id) 
        { 
            // Get the cart 
            var cartItem = storeDB.Carts.Single( 
cart => cart.CartId == ShoppingCartId  
&& cart.RecordId == id); 
  
            int itemCount = 0; 
  
            if (cartItem != null) 
            { 
                if (cartItem.Count > 1) 
                { 
                    cartItem.Count--; 
                    itemCount = cartItem.Count; 
                } 
                else 
                { 
                    storeDB.Carts.Remove(cartItem); 
                } 
                // Save changes 
                storeDB.SaveChanges(); 
            } 
            return itemCount; 
        } 
        public void EmptyCart() 
        { 
            var cartItems = storeDB.Carts.Where(cart => cart.CartId == 
ShoppingCartId); 
  
            foreach (var cartItem in cartItems) 
            { 
                storeDB.Carts.Remove(cartItem); 
            } 
            // Save changes 
            storeDB.SaveChanges(); 
        } 
        public List<Cart> GetCartItems() 
        { 
            return storeDB.Carts.Where(cart => cart.CartId == 
ShoppingCartId).ToList(); 
        } 
        public int GetCount() 
        { 
            // Get the count of each item in the cart and sum them up 
            int? count = (from cartItems in storeDB.Carts 
                          where cartItems.CartId == ShoppingCartId 
                          select (int?)cartItems.Count).Sum(); 
            // Return 0 if all entries are null 
            return count ?? 0; 
        } 
        public decimal GetTotal() 
        { 
            // Multiply album price by count of that album to get  
            // the current price for each of those albums in the cart 
            // sum all album price totals to get the cart total 
            decimal? total = (from cartItems in storeDB.Carts 
                              where cartItems.CartId == ShoppingCartId 
                              select (int?)cartItems.Count * 
cartItems.Album.Price).Sum(); 
            return total ?? decimal.Zero; 
        } 
        public int CreateOrder(Order order) 
        { 
            decimal orderTotal = 0; 
  
            var cartItems = GetCartItems(); 
            // Iterate over the items in the cart, adding the order details for 
each 
            foreach (var item in cartItems) 
            { 
                var orderDetails = new OrderDetail 
                { 
                    AlbumId = item.AlbumId, 
                    OrderId = order.OrderId, 
                    UnitPrice = item.Album.Price, 
                    Quantity = item.Count 
                }; 
                // Set the order total of the shopping cart 
                orderTotal += (item.Count * item.Album.Price); 
            } 
            // Set the order's total to the orderTotal count 
            order.Total = orderTotal; 
  
            // Save the order 
            storeDB.SaveChanges(); 
            // Empty the shopping cart 
            EmptyCart(); 
            // Return the OrderId as the confirmation number 
            return order.OrderId; 
        } 
        // We're using HttpContextBase to allow access to cookies. 
        public string GetCartId(HttpContextBase context) 
        { 
            if (context.Session[CartSessionKey] == null) 
            { 
                if (!string.IsNullOrWhiteSpace(context.User.Identity.Name)) 
                { 
                    context.Session[CartSessionKey] = 
context.User.Identity.Name; 
                } 
                else 
                { 
                    // Generate a new random GUID using System.Guid class 
                    Guid tempCartId = Guid.NewGuid(); 
                    // Send tempCartId back to client as a cookie 
                    context.Session[CartSessionKey] = tempCartId.ToString(); 
                } 
            } 
            return context.Session[CartSessionKey].ToString(); 
        } 
        // When a user has logged in, migrate their shopping cart to 
        // be associated with their username 
        public void MigrateCart(string userName) 
        { 
            var shoppingCart = storeDB.Carts.Where(c => c.CartId == ShoppingCartId); 
  
            foreach (Cart item in shoppingCart) 
            { 
                item.CartId = userName; 
            } 
            storeDB.SaveChanges(); 
        } 
    } 

模型视图
我 们的ShoppingCart需要传递一些复合信息给它的视图,这些信息并没有清晰地映射到模型类。我们不想为了视图而修改模型,模型类应当代表我们的领 域,而不是用户界面。一种解决方法是使用ViewBag传递相关信息,就象之前在StoreManager中为下拉框传递数据一样。但是通过 ViewBag传递太多信息会变得难以管理。

另一种方案是使用视图模型(ViewModels),这种方式可以为指定的视图创建最优的强类型类,并且在视图模板中为所需的值/内容公开属性。控制器可以填充和传递这些“视图优化”类给视图模板使用,而且在视图模板中支持类型安全、编译检查和智能感应器。

我们创建两个视图模型供ShoppingCartController使用:ShoppingCartViewModel保存用户购物车的内容,ShoppingCartRemoveViewModel在用户从购物车移除物品时显示确认信息。

在项目中添加新文件夹ViewModels。

接下来在ViewModels文件夹中添加类ShoppingCartViewModel,它有两个属性:购物车物品集合和购物车所有物品的总金额。

using System.Collections.Generic; 
 using MvcMusicStore.Models; 
  
namespace MvcMusicStore.ViewModels 

    public class ShoppingCartViewModel 
    { 
        public List<Cart> CartItems { get; set; } 
        public decimal CartTotal { get; set; } 
    } 
}

在ViewModels文件夹下添加ShoppingCartRemoveViewModel类:

namespace MvcMusicStore.ViewModels 

    public class ShoppingCartRemoveViewModel 
    { 
        public string Message { get; set; } 
        public decimal CartTotal { get; set; } 
        public int CartCount { get; set; } 
        public int ItemCount { get; set; } 
        public int DeleteId { get; set; } 
    } 
}

Shopping Cart控制器

Shopping Cart控制器有三个主要功能:往购物车添加物品,从购物车中移除物品以及显示购物车的物品。它将使用我们刚刚创建的三个 类:ShoppingCartViewModel, ShoppingCartRemoveViewModel和 ShoppingCart。和StoreController发及StoreManagerController一样,我们为它添加一个 MusicStoreEntities类的实例字段。

在项目中添加一个Shopping Cart控制器:

 下面是完整的ShoppingCartController的代码。Index和Add控制器操作看起来非常眼熟。Remove和CartSummary控制器操作处理两个特殊的事件,我们在下一章讨论它们。

using System.Linq; 
 using System.Web.Mvc; 
 using MvcMusicStore.Models; 
 using MvcMusicStore.ViewModels; 
  
namespace MvcMusicStore.Controllers 

    public class ShoppingCartController : Controller 
    { 
        MusicStoreEntities storeDB = new MusicStoreEntities(); 
        // 
        // GET: /ShoppingCart/ 
        public ActionResult Index() 
        { 
            var cart = ShoppingCart.GetCart(this.HttpContext); 
  
            // Set up our ViewModel 
            var viewModel = new ShoppingCartViewModel 
            { 
                CartItems = cart.GetCartItems(), 
                CartTotal = cart.GetTotal() 
            }; 
            // Return the view 
            return View(viewModel); 
        } 
        // 
        // GET: /Store/AddToCart/5 
        public ActionResult AddToCart(int id) 
        { 
            // Retrieve the album from the database 
            var addedAlbum = storeDB.Albums 
                .Single(album => album.AlbumId == id); 
  
            // Add it to the shopping cart 
            var cart = ShoppingCart.GetCart(this.HttpContext); 
  
            cart.AddToCart(addedAlbum); 
  
            // Go back to the main store page for more shopping 
            return RedirectToAction("Index"); 
        } 
        // 
        // AJAX: /ShoppingCart/RemoveFromCart/5 
        [HttpPost] 
        public ActionResult RemoveFromCart(int id) 
        { 
            // Remove the item from the cart 
            var cart = ShoppingCart.GetCart(this.HttpContext); 
  
            // Get the name of the album to display confirmation 
            string albumName = storeDB.Carts 
                .Single(item => item.RecordId == id).Album.Title; 
  
            // Remove from cart 
            int itemCount = cart.RemoveFromCart(id); 
  
            // Display the confirmation message 
            var results = new ShoppingCartRemoveViewModel 
            { 
                Message = Server.HtmlEncode(albumName) + 
                    " has been removed from your shopping cart.", 
                CartTotal = cart.GetTotal(), 
                CartCount = cart.GetCount(), 
                ItemCount = itemCount, 
                DeleteId = id 
            }; 
            return Json(results); 
        } 
        // 
        // GET: /ShoppingCart/CartSummary 
        [ChildActionOnly] 
        public ActionResult CartSummary() 
        { 
            var cart = ShoppingCart.GetCart(this.HttpContext); 
  
            ViewData["CartCount"] = cart.GetCount(); 
            return PartialView("CartSummary"); 
        } 
    } 
}

使用Ajax.ActionLink实现Ajax更新

为ShoppingCartViewModel类创建一个强类型的Shopping Cart Index页面,并且象以前一样使用List视图模板。

 (注:这里实际上不能在“支架模板”中选择List,否则生成视图后直接运行会出错。因为Index方法返回的是单个ShoppingCartViewModel对象而不是集合。当然你可以直接复制网页上的代码来覆盖自动生成的代码,不过你还是要明白这一点)

使用Ajax.ActionLink代替Html.ActionLink来生成从购物车移除物品的链接。

@Ajax.ActionLink("Remove from cart", 
"RemoveFromCart",  
    new { id = item.RecordId }, new AjaxOptions { OnSuccess = "handleUpdate" 
})

Ajax.ActionLink 和Html.ActionLink方法非常相似,不同的是表单提交时为RemoveFromCart方法生成一个Ajax回调。 RemoveFromCart方法返回一个序列化的JsonResult对象(关于JsonResult对象,请参见:http://msdn.microsoft.com/zh-cn/library/system.web.mvc.jsonresult.aspx) ,它被自动传递给AjaxOptions的OnSuccess参数指定的JavaScript方法,在本例中,这个方法是handleUpdate。handleUpdate使用JQuery为页面执行四个快速更新:

  • 1.从列表中移除删掉的唱片
  • 2.更新标题中的数量
  • 3.为用户显示更新信息
  • 4.更新购物车总金额

由于Index视图使用Ajax回调来处理“移除”情况,我们不需要为RemoveFromCart操作添加任何视图,完整代码如下:

@model MvcMusicStore.ViewModels.ShoppingCartViewModel 
@{ 
    ViewBag.Title = "Shopping Cart"; 

<script src="/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script> 
<script type="text/javascript"> 
    $(function () { 
        // Document.ready -> link up remove event handler 
        $(".RemoveLink").click(function () { 
            // Get the id from the link 
            var recordToDelete = $(this).attr("data-id"); 
            if (recordToDelete != '') { 
                // Perform the ajax post 
                $.post("/ShoppingCart/RemoveFromCart", { "id": 
recordToDelete }, 
                    function (data) { 
                        // Successful requests get here 
                        // Update the page elements 
                        if (data.ItemCount == 0) { 
                            $('#row-' + data.DeleteId).fadeOut('slow'); 
                        } else { 
                            $('#item-count-' + 
data.DeleteId).text(data.ItemCount); 
                        } 
                        $('#cart-total').text(data.CartTotal); 
                        $('#update-message').text(data.Message); 
                        $('#cart-status').text('Cart (' + data.CartCount + ')'); 
                    }); 
            } 
        }); 
    }); 
    function handleUpdate() { 
        // Load and deserialize the returned JSON data 
        var json = context.get_data(); 
        var data = Sys.Serialization.JavaScriptSerializer.deserialize(json); 
  
        // Update the page elements 
        if (data.ItemCount == 0) { 
            $('#row-' + data.DeleteId).fadeOut('slow'); 
        } else { 
            $('#item-count-' + data.DeleteId).text(data.ItemCount); 
        } 
        $('#cart-total').text(data.CartTotal); 
        $('#update-message').text(data.Message); 
        $('#cart-status').text('Cart (' + data.CartCount + ')'); 
    } 
</script> 
<h3> 
    <em>Review</em> your cart: 
 </h3> 
<p class="button"> 
    @Html.ActionLink("Checkout 
>>", "AddressAndPayment", "Checkout") 
</p> 
<div id="update-message"> 
</div> 
<table> 
    <tr> 
        <th> 
            Album Name 
        </th> 
        <th> 
            Price (each) 
        </th> 
        <th> 
            Quantity 
        </th> 
        <th></th> 
    </tr> 
    @foreach (var item in 
Model.CartItems) 
    { 
        <tr id="row-@item.RecordId"> 
            <td> 
                @Html.ActionLink(item.Album.Title, 
"Details", "Store", new { id = item.AlbumId }, null) 
            </td> 
            <td> 
                @item.Album.Price 
            </td> 
            <td id="item-count-@item.RecordId"> 
                @item.Count 
            </td> 
            <td> 
                <a href="#" class="RemoveLink" data-id="@item.RecordId">Remove from cart</a> 
            </td> 
        </tr> 
    } 
    <tr> 
        <td> 
            Total 
        </td> 
        <td> 
        </td> 
        <td> 
        </td> 
        <td id="cart-total"> 
            @Model.CartTotal 
        </td> 
    </tr> 
</table>

要测试上面的代码,我们先更新Store Details视图,添加一个“Add to cart”按纽,我们还可以为唱片追加一些相关信息: Genre, Artist, Price, t和Album Art。更新后的Store Details视图代码如下:

@model MvcMusicStore.Models.Album 
@{ 
    ViewBag.Title = "Album - " + Model.Title; 
 } 
<h2>@Model.Title</h2> 
<p> 
    <img alt="@Model.Title" 
src="@Model.AlbumArtUrl" /> 
</p> 
<div id="album-details"> 
    <p> 
        <em>Genre:</em> 
        @Model.Genre.Name 
    </p> 
    <p> 
        <em>Artist:</em> 
        @Model.Artist.Name 
    </p> 
    <p> 
        <em>Price:</em> 
        @String.Format("{0:F}", 
Model.Price) 
    </p> 
    <p class="button"> 
        @Html.ActionLink("Add to 
cart", "AddToCart",  
        "ShoppingCart", new { id = Model.AlbumId }, "") 
    </p> 
</div>

现在我们可以通过点击“Store”来测试对购物车添加和移除物品,运行应用程序并访问/Store:

 

点击某个类别查看唱片列表:

 点击唱片标题进入更新后的Store Details视图:

 点击“Add to cart”按纽,在Shopping Cart的首页中显示购物车清单:

 购物车被加载之后,你可以点击“Remove from cart”链接查看Ajax的更新效果。

 我们建立了购物车,让用户无需注册就可以往购物车中添加物品,下一章,我们将允许他们注册以完成结算过程。

 

时间: 2024-10-03 21:24:57

ASP.NET MVC Music Store教程(8):购物车和AJAX更新的相关文章

ASP.NET MVC Music Store教程(3):视图和视图模型

转自http://firechun.blog.163.com/blog/static/31804522201102711480936/ 到目前为止,我们仅仅从控制器动作返回字符串,这是一个了解控制器如何工作的好方法,但这并不是你想要的真实的Web应用程序.我们想要一个更好的方法为访问我们站点的浏览器产生HTML,使用模板文件可以更容易地定制发回的HTML内容. 添加视图模板 要使用视图模板,可以修改HomeController的Index方法,让它返回ActionResult,就象下面这样返回V

ASP.NET MVC Music Store教程(1):概述和新项目

转自 http://firechun.blog.163.com/blog/static/3180452220110270937467/ 本文转自http://www.asp.net/mvc,由本人翻译整理. 1 月31日补充:打算在公司的新项目中使用MVC,因此想把这篇文章翻译过来,做为公司开发小组的参考资料.最初看到这篇文章时,作者是用MVC 2实现的,但现在已经是针对MVC 3写的教程了.原来担心微软新推出的产品总是不太令人放心,加上教程中使用了Razor语法,不想让开发小组成员因为学习太多

ASP.NET MVC Music Store教程(4):模型和数据访问

转自http://firechun.blog.163.com/blog/static/318045222011029105328664/ 迄今为止,我们只是把"模拟数据"从控制器传递到视图模板,现在,我们要挂上真实的数据库了.在教程中,我们演示了如何使用免费的SQL Server Express做为我们的数据库引擎,这些代码也同样适用于完整版的SQL Server. 首先在项目中添加App_Data目录存放SQL Server Express数据库文件.App_Data是ASP.NET

ASP.NET MVC Music Store教程(5):编辑表单和模板

转自http://firechun.blog.163.com/blog/static/3180452220110303730942/ 在上一章,我们加载并显示了数据,这一章中,我们将对数据进行编辑. 我们创建一个新的控制器--StoreManagerController,这个控制器支持Create和Update操作,创建控制器时,把"为Create.Update.Delete和Details方案添加操作方法"勾选上: 这将生成一个包括通用的"增删改查"方法存根的类,

ASP.NET MVC Music Store教程(2):控制器

转自http://firechun.blog.163.com/blog/static/3180452220110272197830/ 在传统的Web架构中,URL总是映射到磁盘上的文件.例如:一个类似于"/Products.aspx"或"/Products.php"的URL可能由"Products.aspx"或"Products.php"文件来处理. 在基于MVC的Web架构中,URL的映射有一些不同,映射到文件被替换成映射到

ASP.NET MVC Music Store教程(6):使用数据注释为模型进行验证

转自http://firechun.blog.163.com/blog/static/31804522201103133832931/ 在Edit和Create表单中有一个很严重的问题:没有做任何验证.我们可以试一下让必填字段为空或者在价格字段中输入字母,我们将会看到一个来自数据库的错误. 为应用程序的模型类添加数据注释(Data Annotations)让我们对数据进行验证变得很容易,数据注释可以让我们描述要应用到模型属性上的规则,ASP.NET MVC会强制应用这些规则并显示恰当的消息给用户

在Asp.net MVC使用thickbox实现调用页面的Ajax更新

在MVC模式中,通常都是Controller处理请求并生成数据,选择一个合适的 View来显示结果给用户.虽然Asp.net MVC已经有非常丰富的ActionResult来满 足不同情况下的需求,但是有了Ajax的利器,我们希望有更流畅的交互方式.我 们希望能够在一个界面完成列表的显示,编辑或者新增,并完成刷新.借助 jQuery的一个扩展thickbox我们能够达到这个效果. 本文的灵感来自于一篇博文:MVC AJAX Form with Ajax.BeginForm() and jQuer

ASP.NET MVC 5 学习教程:创建连接字符串

原文 ASP.NET MVC 5 学习教程:创建连接字符串 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 通过控制器访问模型的数据 生成的代码详解 使用 SQL Server LocalDB Edit方法和Edit视图详解 添加查询 Entity Framework 数据迁移之添加字段 添加验证 Details 和 Delete 方法详解 在上一节中,我们创建了MovieDBContext 类来连接数据

ASP.NET MVC 5 学习教程:添加验证

原文 ASP.NET MVC 5 学习教程:添加验证 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 通过控制器访问模型的数据 生成的代码详解 使用 SQL Server LocalDB Edit方法和Edit视图详解 添加查询 Entity Framework 数据迁移之添加字段 添加验证 Details 和 Delete 方法详解 在本节中,我们将为Movie模型添加验证逻辑,并确认验证规则在用户试图