ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第六章:管理产品图片:多对多关系(上)

这章介绍了怎样创建一个新的实体来管理图片,怎样使用HTML窗体来上传图片文件和使用多对多关系来使它们与产品相关,并且怎样来保存图片到文件系统中。这章也介绍了更多复杂的错误处理增加客户端错误到模型中为了把它们显示回给用户。在这章中播种数据库使用的产品图片可能在在第六章的从Apress网页站点下载代码中。

注意:如果你想遵从这章的代码,你必须完成第五章的代码或者从www.apress.com下载第五章的源代码作为一个起点。

创建实体保存图片文件名

这个项目,我们正要使用文件系统在Web项目中存储图片文件,数据库将包含与一个或多个产品有关的文件系统名称的图像的数据。开始建模图像存储,就像以下一样在Models文件夹下添加一个新的类命名为ProductImage:

 1   using System.ComponentModel.DataAnnotations;
 2
 3 namespace BabyStore,Models
 4
 5 {
 6
 7      public class ProductImage
 8
 9     {
10
11         public int ID{get;set;}
12
13        [Display(Name="File")]
14
15        public string FileName{get;set;}
16
17     }
18
19 }

你可能疑惑我们为什么添加一个额外的类基本上一个产品应对一个字符串而不是简单地添加一个字符串集合到Product类里。这是一个普遍的问题被开发者提及当使用实体框架时。原因是实体框架不能在数据库里建模一个字符串集合;它需要集合被建模就像我们做过的字符串储存在一个特别的类里。

现在更新DAL\StoreContext.cs文件来添加一个新的ProductImages属性:

 1 using BabyStore.Models;
 2
 3     using System.Data.Entity;
 4
 5    namespace BabyStore.DAL
 6
 7   {
 8
 9           public class StoreContext:DbContext
10
11         {
12
13              public DbSet<Product> Products{get;set;}
14
15             public DbSet<Category> Categories{get;set;}
16
17             public DbSet<ProductImage> ProductImages{get;set;}
18
19         }
20
21   }

接下来,创建一个迁移添加新的ProductImage实体作为一个表通过输入add-migration ProductImages到Package Manager Console中并按返回。然后运行update-database命令来更新数据库并且创建新的ProductImages表。

   上传图片

在我们上传任何图片之前,我们需要某个地方来存储它们。就按之前规定的,我们正要存储它们在文件系统而不是数据库所以在更目录下创建一个新的文件夹并且命名为ProductImages,在ProductImages文件夹下,创建一个新的文件夹命名为Thumbnails。

ProductImages文件夹将拥有被上传的图片并且Thumbnails文件夹将含有在轮播特色里使用的小图片来允许一个用户通过每个产品图片来导航。

定义可利用的内容

我们正要通过项目在各种各样的文件里参考这些文件夹;因此,我们需要一种方法来存储每个文件夹的路径以便我们能容易地参考它们。为了做这个,我们要在项目的基础上添加一个新的命名为Constants的静态类并且为了这2个文件路径添加一些内容。为了做这个,在解决浏览器中右击BabyStore项目并选择【添加】->【类】。创建一个新的命名为Constants的类,用以下的代码来更新新的类:

 1 namespace BabyStore
 2
 3 {
 4
 5     public static class Constants
 6
 7    {
 8
 9        public const string ProductImagePath="~/Content/ProductImages/";
10
11        public const string ProductThumbnailPath="~/Content/ProductImages/Thumbnails/";
12
13    }
14
15 }

当我们需要引用储存图片的文件路径时,我们将参考Constants类。这个类被声明为静态的所以它不需要在被使用之前实例化。

既然我们有全局化被定义的常数,添加一个PageItems常量(当前在ProductsController类里定义)就像高亮显示的:

 1 namespace BabyStore
 2
 3   {
 4
 5          public static class Constants
 6
 7        {
 8
 9             public const string ProductImagePath="~/Content/ProductImages/";
10
11             public const string ProductThumbnailPath="~/Content/ProductImages/Thumbnails/";
12
13             public const int PageItems=3;
14
15        }
16
17   }

更新ProductsController类里的Index方法通过从中删除当前的PageItems常量来使用这个新的常量,就像以下:

 1 public ActionResult Index(string category, string search, string sortBy, int? page)
 2 {
 3 //instantiate a new view model
 4 ProductIndexViewModel viewModel = new ProductIndexViewModel();
 5 //select the products
 6 var products = db.Products.Include(p => p.Category);
 7 //perform the search and save the search string to the viewModel
 8 if (!String.IsNullOrEmpty(search))
 9 {
10 products = products.Where(p => p.Name.Contains(search) ||
11 p.Description.Contains(search) ||
12 p.Category.Name.Contains(search));
13 viewModel.Search = search;
14 }
15 //group search results into categories and count how many items in each category
16 viewModel.CatsWithCount = from matchingProducts in products
17 where
18 matchingProducts.CategoryID != null
19 group matchingProducts by
20 matchingProducts.Category.Name into
21 catGroup
22 select new CategoryWithCount()
23 {
24 CategoryName = catGroup.Key,
25 ProductCount = catGroup.Count()
26 };
27 if (!String.IsNullOrEmpty(category))
28 {
29 products = products.Where(p => p.Category.Name == category);
30 viewModel.Category = category;
31 }
32 //sort the results
33 switch (sortBy)
34 {
35 case "price_lowest":
36 products = products.OrderBy(p => p.Price);
37 break;
38 case "price_highest":
39 products = products.OrderByDescending(p => p.Price);
40 break;
41 default:
42 products = products.OrderBy(p => p.Name);
43 break;
44 }
45 int currentPage = (page ?? 1);
46 viewModel.Products = products.ToPagedList(currentPage, Constants.PageItems );
47 viewModel.SortBy = sortBy;
48 viewModel.Sorts = new Dictionary<string, string>
49 {
50 {"Price low to high", "price_lowest" },
51 {"Price high to low", "price_highest" }
52 };
53 return View(viewModel);
54 }

添加一个ProductImage 控制器和视图

接下来,生成解决方案并添加一个ProductImages控制器和与它相关的视图。做这个通过右击Controllers文件夹并随后从菜单选择添加控制器。在选项里选择添加带视图的MVC5控制器,使用实体框架,单击添加按钮。

接下来添加一个命名为ProductImagesControllor的控制器,确认ProductImage作为Model,和使StoreContext类作为数据的上下文。确认所有的视图选项被选中,就像图6-1显示的:

图6-1添加一个ProductImages控制器选项

一旦被创建,一个新的ProductImagesController类应该出现在Controllers文件夹里和与之联系的增删改查视图应该出现在Views\ProductImages文件夹下。

我们首先要修改的是Create方法和与ProductImages相关联的Create视图。如果你开始网页站点并导航到/ProductImages/Create,你将看到一个与类别的Create页很接近的页面,它允许用户输入一个不是很必要的字符串,所必要的东西是一个Create方法和有能力上传一个文件的Create视图,保存它到本地和添加文件名到数据库。

      为文件上传更新ProductImagesController类

开始上传文件,我们正要添加许多方法到ProductImagesController类来验证文件大小和上传的格式并调整图片尺寸到合适的大小来显示在网页站点里。这代码常常应该被分离成特别的可用的验证文件的类,但对于这个示例项目,我们正把这些存在ProductImagesController类里,使它更容易地学习。

添加以下的方法到Controllers/ProductsImagesController.cs文件里的Dispose()方法下面:

 1 private bool ValidateFile(HttpPostedFileBase file)
 2 {
 3    string fileExtension=System.IO.Path.GetExtension(file.FileName).ToLower();
 4   string[] allowedFileTypes={".gif",".png",".Jpeg",".jpg"};
 5   if((file.ContentLength>0&&file.ContentLength<2097152)&&allowedFileType.Contains(fileExtension))
 6 {
 7       return true;
 8 }
 9 return false;
10 }

新的方法返回一个布尔值并且带有一个参数,这参数命名为HttpPostedFileBase的file。这个方法包含文件的扩展名并且检查看文件是否是允许的扩展名(GIF,PNG,JPEG和JPG)。它也检查文件的大小是不是在0bytes和2MB之间。如果是,方法返回True(否则,返回false)。有一点要注意,我们使用Linq包含操作符来缩短大量的必要代码,而不是遍及allowedFileTypes数组来循环。
   接下来,在ValidateFile()方法下添加一个新的方法,这个方法将被用来调整图片如果有需要的话并且然后保存它们到磁盘,如下:

 1 private void SaveFileToDisk(HttpPostedFileBase file)
 2 {
 3      WebImage img=new WebImage(file.InputStream);
 4     if(img.Width>190)
 5    {
 6        img.Resize(190,img.height);
 7    }
 8  img.Save(Constents.ProductImagePath+file.FileName);
 9    if(img.Width>100)
10   {
11         img.Resize(100,img.Height);
12   }
13  img.Save(Constents.ProductThumbnailPath+file.FileName);
14 }

保证这代码编译,确定你添加了这个using语句在文件的顶部:using System.Web.Helpers;

SaveFileToDisk()方法再次输入一个HttpPostedFileBase类型的输入参数文件。然后它使用WebImage类来调整图像如果宽度大于190像素并且把它保存到ProductImages目录。然后有必要的话它调整图像宽度到100像素以下,并且保存它到thumbnails目录。

既然我们有helper方法在对的地方,我们有必要修改ProductController类的Create()方法来上传文件当Product被创建。首先,重命名Create()方法为Upload()。更新Upload()方法的HttpPost版本,就像粗体光亮的那个:

 1 [HttpPost]
 2 [ValidateAntiForgeryToken]
 3 public ActionResult Upload( HttpPostedFileBase file )
 4 {
 5 //check the user has entered a file
 6 if (file != null)
 7 {
 8 //check if the file is valid
 9 if (ValidateFile(file))
10 {
11 try
12 {
13 SaveFileToDisk(file);
14 }
15 catch (Exception)
16 {
17    ModelState.AddModelError("FileName", "Sorry an error occurred saving the file
18 to disk, please try again");
19 }
20 }
21 else
22 {
23 ModelState.AddModelError("FileName", "The file must be gif, png, jpeg or jpg and
24 less than 2MB in size");
25 }
26 }
27 else
28 {
29 //if the user has not entered a file return an error message
30 ModelState.AddModelError("FileName", "Please choose a file");
31 }
32 if (ModelState.IsValid)
33 {
34 db.ProductImages.Add( new ProductImage { FileName = file.FileName } );
35 db.SaveChanges();
36 return RedirectToAction("Index");
37 }
38 return View();
39 }

我们所做的第一个更改就是完全移除Bind部分因为ID被数据库设置并且我们是正要手动设置FileName属性。我们然后移除ProductImage参数并且添加一个新的输入参数:HttpPostedFileBase[]file。这个参数是一个被用户提交的文件并且在视图中从文件上传控件填充。在这方法中我们通过手动执行数据分配而不依赖模型绑定,所以方法不需要productImage参数。反而在这行代码中,当添加ProductImage到数据库中时,我们创建了一个ProductImage对象:db.ProductImages.Add(new ProductImage{FileName=file.FileName});

然后,我们添加了一个if语句来检查用户是否实际上输入了一个文件。如果他们没有输入,那么我们使用ModelState.AddError()方法来添加一个错误来提醒他们他们需要输入一个文件就如下:

1 //check the user has entered a file
2 if (file != null)
3 {
4 }
5 else
6 {
7 //if the user has not entered a file return an error message
8 ModelState.AddModelError("FileName", "Please choose a file");
9 }

如果用户已经输入一个文件,然后一个检查被运行来确定那个文件是“有效”的,例如,它大小不是大于2MB和是一个允许的格式,如果是的,将使用SaveFileToDisk()方法把文件存入磁盘。如果文件不是“有效的”,然后一个模型错误被添加来提醒用户“文件必须是gif,png,jpeg或者jpg格式并且大小要小于2MB”。所有这些都发生在下面的代码中:

 1 //check if the file is valid
 2 if (ValidateFile(file))
 3 {
 4 try
 5 {
 6 SaveFileToDisk(file);
 7 }
 8 catch (Exception)
 9 {
10 ModelState.AddModelError("FileName", "Sorry an error occurred saving the file to disk,
11 please try again");
12 }
13 }
14 else
15 {
16 ModelState.AddModelError("FileName", "The file must be gif, png, jpeg or jpg and less than
17 2MB in size");
18 }

最终,如果一切都成功了并且ModelState仍旧有效,一个新的带有FileName属性的ProductImage被创建设置为提交文件的文件名并保存到数据库中。用户然后被转向到Index视图;否则,如果有错误在ModelState里,upload视图返回给用户并且显示错误信息用以下的代码:

1 if (ModelState.IsValid)
2 {
3 db.ProductImages.Add(new ProductImage { FileName = file.FileName });
4 db.SaveChanges();
5 return RedirectToAction("Index");
6 }
7 return View();

     更新视图

现在我们已经更新了控制器,我们必须更新视图文件以便它包含一个控件提交表单而不是一个字符串。首先重命名\Views\ProductImages\Create.cshtml文件为Upload.cshtml。接下去修改文件来允许用户通过HTML表单来提交文件:

 1 @model BabyStore.Models.ProductImage
 2 @{
 3 ViewBag.Title = " Upload Product Image ";
 4 }
 5 <h2>@ViewBag.Title</h2>
 6 @using (Html.BeginForm("Upload", "ProductImages", FormMethod.Post, new { enctype =
 7 "multipart/form-data" }))
 8 {
 9 @Html.AntiForgeryToken()
10 <div class="form-horizontal">
11 @Html.ValidationSummary(true, "", new { @class = "text-danger" })
12 <div class="form-group">
13 @Html.LabelFor(model => model.FileName, htmlAttributes: new { @class = "controllabel
14 col-md-2" })
15 <div class="col-md-10">
16 <input type="file" name="file" id="file" class="form-control"/>
17 @Html.ValidationMessageFor(model => model.FileName, "", new { @class = "textdanger"
18 })
19 </div>
20 </div>
21 <div class="form-group">
22 <div class="col-md-offset-2 col-md-10">
23 <input type="submit" value=" Upload " class="btn btn-default" />
24 </div>
25 </div>
26 </div>
27 }
28 <div>
29 @Html.ActionLink("Back to List", "Index")
30 </div>
31 @section Scripts {
32 @Scripts.Render("~/bundles/jqueryval")
33 }

更新页面标题的第一个改变前一章更新其他页面的方式相似。然后我们更新表单有enctype="multipart/form-data"的html属性,因为这对于uploading文件是必要的。这是用@using(Html.BeginForm("Upload","ProductImages",FormMethod.Post,new{enctype="multipart/form-data"}))语句获得。
   接下来必要的改变就是使用代码:<input type="file" id="file" class="form-control"/>改变一个HTML文件上传控件的表单输入。其他的改变只有改变按钮文字为"Upload"。图6-2显示了结果的HTML页面。

图6-2有上传控件的ProductImages上传HTML页面

最终必要的改变就是添加一些到新视图的链接。修改\View\Shared\_Layout.cshtml文件,添加一个新的到ProductImages Index页面的链接通过修改无序列表(<ul>HTML标签)伴随着nav navbar-nav样式:

1 <ul class="nav navbar-nav">
2 <li>@Html.ActionLink("Home", "Index", "Home")</li>
3 <li>@Html.ActionLink("Shop by Category", "Index", "Categories")</li>
4 <li>@Html.RouteLink("View all our Products", "ProductsIndex")</li>
5 <li>@Html.ActionLink("Manage Images", "Index", "ProductImages")</li>
6 </ul>

跟随这个修改Views\ProductImages\Index.cshtml文件来改变这行代码为了创建一个到新的Upload视图:

1 @Html.ActionLink("Create New", "Create") to @Html.ActionLink("Upload New Image", "Upload")

测试文件上传

开始网页站点并导航到ProductImages Upload页面,然后单击Upload按钮不要输入文件。页面将显示一个错误信息就像图6-3所示:

图6-3 当用户不选择一个文件上传时显示的错误信息

接着这个测试,从Apress网页站点下载CH6解决方案。现在试着上传Bitmap01文件从下载下来的解决方案里的ProductImages文件夹里。网页站点应该回应一个错误信息就像图6-4显示的;接下来试着上传大图像文件。这是一个JPG文件超过了2MB,所以网页站点应该回应就像图6-4那样。

图6-4当企图上传无效文件时显示在用户面前的错误信息

接下来,试着上传Image01文件,上传将被允许。数据库表dbo.ProductImages将包含一条Image1的记录,就像图6-5显示的,并且图片将被重新调整大小如果需要的话并且存储在Web应用程序的Content\ProductImages和Content\ProductImages\Thumbnails文件夹里。图片将出现在解决方案浏览器的这些目录下面,就像图6-6显示的。在Content\ProductImages文件夹里的图片宽度将调整为190像素和在Thumbnails文件夹里的图片宽度为100像素,随着纵横比保持两倍。

图6-5一个新的Image01记录存储在ProductImages表中

图6-6 Image01.jpg图片存储在Content\ProductImages和Content\ProductImages\Thumbnails目录里

使用实体框架检查唯一记录

文件上传现在工作了,然而用户能够上传相同文件到系统中不止一次。理论上这是不被允许的。所以要阻止它发生,我们正要添加一个不是数据库的唯一约束。为了完成它,我们正要在FileName域上使用一个Index。更新Models\ProductImage.cs文件像以下那样:

 1 using System.ComponentModel.DataAnnotations;
 2 using System.ComponentModel.DataAnnotations.Schema;
 3 namespace BabyStore.Models
 4 {
 5 public class ProductImage
 6 {
 7 public int ID { get; set; }
 8 [Display(Name = "File")]
 9 [StringLength(100)]
10 [Index(IsUnique = true)]
11 public string FileName { get; set; }
12 }
13 }

这代码添加了唯一约束并应用了一个FileName域的最大长度以便它不再设置为nvarchar[MAX]。这是需要的,因为SQL Server为索引关键字提供了一个最大900字节并且没有它的话,应用索引将会失败。

添加一个新的迁移UniqueFileName通过键入以下命令到包管理控制台并且按返回:add-migration UniqueFileName。接着运行update-database命令。

数据库现在将有一个索引应用来确定FileName列为唯一。这个索引将阻止在FileName列里重复输入并且当企图重复输入时SQL Server 将抛出一个错误。

试着再一次上传Image01文件。图6-7显示了网页站点现在怎样响应。

图6-7当试着在SQL Server里添加重复记录到唯一索引列时响应了标准的网页站点错误

为了显示许多更有意义的信息给用户,我们有必要添加许多错误处理以便网页站点能在视图里响应一个错误而不是标准的生成的错误信息,添加错误处理,改变在ProductImagesController类里的Upload方法的HttpPost版本:

 1 [HttpPost]
 2 [ValidateAntiForgeryToken]
 3 public ActionResult Upload(HttpPostedFileBase file)
 4 {
 5 //check the user has entered a file
 6 if (file != null)
 7 {
 8 //check if the file is valid
 9 if (ValidateFile(file))
10 {
11 try
12 {
13 SaveFileToDisk(file);
14 }
15 catch (Exception)
16 {
17 ModelState.AddModelError("FileName", "Sorry an error occurred saving the file
18 to disk, please try again");
19 }
20 }
21 else
22 {
23 ModelState.AddModelError("FileName", "The file must be gif, png, jpeg or jpg
24 and less than 2MB in size");
25 }
26 }
27 else
28 {
29 //if the user has not entered a file return an error message
30 ModelState.AddModelError("FileName", "Please choose a file");
31 }
32 if (ModelState.IsValid)
33 {
34 db.ProductImages.Add(new ProductImage { FileName = file.FileName });
35 try
36 {
37 db.SaveChanges();
38 }
39 catch (DbUpdateException ex)
40 {
41 SqlException innerException = ex.InnerException.InnerException as SqlException;
42 if (innerException != null && innerException.Number == 2601)
43 {
44 ModelState.AddModelError("FileName", "The file " + file.FileName +
45 " already exists in the system. Please delete it and try again if you wish
46 to re-add it");
47 }
48 else
49 {
50 ModelState.AddModelError("FileName", "Sorry an error has occurred saving to
51 the database, please try again");
52 }
53 return View();
54 }
55 return RedirectToAction("Index");
56 }
57 return View();
58 }

也添加下面的2个using语句在类的顶部以便DbUpdateException和SqlException能被发现:

using System.Data.SqlClient;
using System.Data.Entity.Infrastructure;

代码使用了一个try catch语句企图保存数据库更改或者抓住一个DBUpdateException类型的异常。它然后检查exception的InnerException属性检查它是否是2601号异常(这是一个SQL 异常号试着输入一个重复键当一个唯一索引在表中的地方)如果异常号是2601,然后一个错误被添加到ModelState通知用户文件已经存在。如果异常是不同的号,一个更通用的错误被抛出。最终,如果有一个异常,Update视图被返回给用户来显示错误信息。

如果现在试着上传Image01.jpg文件,网页站点响应像图6-8那样,而不是抛出一个标准的错误信息。

图6-8当试着上传一个重复文件时新的try catch语句创造的错误信息

时间: 2024-12-26 18:13:22

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第六章:管理产品图片:多对多关系(上)的相关文章

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第三章:搜索、高级过滤和视图模型

在这一章中,我们首先添加一个搜索产品的模块以增强站点的功能,然后使用视图模型而不是ViewBag向视图传递复杂数据. 注意:如果你想按照本章的代码编写示例,你必须完成第二章或者直接从www.apress.com下载第二章的源代码. 3.1 添加产品搜索 为了执行产品搜索,我们将添加一些功能使其能够按照产品名称.描述和分类进行搜索,从而让用户有一个更好的选择来查找相关结果. 之所以将分类也包含在内,是因为如果用户输入的是"clothes",而不是一件特定的衣服,那么所有的衣服都会被搜索到

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之目录导航

ASP.NET MVC with Entity Framework and CSS是2016年出版的一本比较新的.关于ASP.NET MVC.EF以及CSS技术的图书,我将尝试着翻译本书以供日后查阅.但是,由于本人英语水平有限,难免有翻译不准确或错误的地方,请大家踊跃提出宝贵的意见,以进行修正.本书一共18章,下面列出各章的英文目录: Chapter 1: Building a Basic MVC Web Site Chapter 2: Creating Views, Controllers,

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第一章:创建基本的MVC Web站点

在这一章中,我们将学习如何使用基架快速搭建和运行一个简单的Microsoft ASP.NET MVC Web站点.在我们马上投入学习和编码之前,我们首先了解一些有关ASP.NET MVC和Entity Framework的背景信息,然后再详细学习如何搭建开发环境. 1.1 MVC和ASP.NET MVC 这本书涵盖Microsoft版本的MVC,即ASP.NET MVC.在写本书的时候,ASP.NET MVC的生产版本为MVC5,因此,本书的示例代码都使用ASP.NET MVC 5编写.在本书中

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类.指定数据库连接字符串以及创建一个数据库.最后,我们还将添加视图和控制器来管理和显式产品和分类数据. 注意:如果你想按照本章的代码编写示例,你必须完成第一章或者直接从www.apress.com下载第一章的源代码. 2.1 添加模型类 Entity Framework的代码优先模式允许我们从模型类创

ASP.NET MVC+EasyUI+Entity FrameWork 整合开发

本文详细讲解怎么用ASP.NET MVC+EasyUI+Entity FrameWork 来开发一个项目 对于ASP.NET MVC的Jscript库,主要引用 <script type="text/javascript" src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")"></script> <script src="@Url.Content("

《Entity Framework 6 Recipes》中文翻译系列 目录篇 -持续更新

为了方便大家的阅读和学习,也是响应网友的建议,在这里为这个系列做一个目录.在目录开始这前,我先来回答之前遇到的几个问题. 1.为什么要学习EF? 这个问题很简单,项目需要.这不像学校,没人强迫你学习! 我学习EF的原因主要是: a.EF是微软推荐的数据库访问技术: b.能提高我的开发效率,我不喜欢写那密密麻麻的SQL: c.比我写的SQL更合理,更快.目前EF生成的SQL的质量已经很高了.你比较熟悉SQL的话,那它在速度上肯定比不上你,新手的话就别跟我争快慢了,能写一像样的SQL就不错了.至少我

《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架,它支持3种不同的技术来创建websites(网站)和Web应用:他们分别是,Web Pages,Web Forms,和MVC.虽然MVC是一种非常流行的,有完整的用于软件开发模式理论的技术,但它在ASP.NET中却是一种新的技术. 目前最新的版本是2012年发布的ASP.NET MVC4.自从2008年发布

Asp.Net MVC 使用Entity Framework创建模型类

先来说说LINQ to SQL和Entity Framework的区别: LINQ to SQL和Entity Framework都是一种包含LINQ功能的对象关系映射技术.他们之间的本质区别在于EF对数据库架构和我们查询的类型实行了更好的解耦.使用EF,我们查询的对象不再是完全对应数据库架构的C#类,而是更高层的抽象:Entity Data Model.这为我们提供了额外的灵活性,但是在性能和简单性上面也会有所损失. LINQ to SQL和Entity Framework各有所长,LINQ

《Entity Framework 6 Recipes》中文翻译系列 (45) ------ 第八章 POCO之获取原始对象与手工同步对象图和变化跟踪器

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-6  获取原始对象 问题 你正在使用POCO,想从数据库获取原始对象. 解决方案 假设你有如图8-7所示的模型.你正在离线环境下工作,你想应用在获取客户端修改之前,使用Where从句和FirstDefault()方法从数据库中获取原始对象. 图8-7.包含一个单独实体Item的模型 按代码清单8-9的方式,在获取实体之后,使用新值更新实体并将其保存到数据库中. 代码清单8-9. 获取最新