来个目录吧:

第一章-入门

第二章- Entity Framework Core Nuget包管理

第三章-创建、修改、删除、查询

第四章-排序、过滤、分页、分组

第五章-迁移,EF Core 的codefirst使用

暂时就这么多。后面陆续更新吧

Entity Framework Core Nuget包管理

如果你创建项目的时候启用了个人身份验证的话,项目中就已经包含了EFCore的支持。

如果你是单纯的空项目想将EFCore添加到你的项目中话,你需要安装一下的Nuget程序包:

vs2017可以直接进行编辑项目的.csproj文件,安装所需软件包。

···











···

(您可以编辑的.csproj文件右击解决方案资源管理器中的项目名称并选择编辑 ContosoUniversity.csproj)。

我又来了,我亲测了下.NETCORE1.1目前不支持Microsoft.EntityFrameworkCore.Tools.DotNet这样玩,这里先略过

创建数据模型

创建Contoso大学实体前,说下他们的关联关系吧。

Student 和Enrollment 的实体关系为一对多。

Course和Enrollment的实体关系同样为一对多。

简单来说就是一个学生可以参加任意一门课程,而一门课程可以有很多个学生。(当然同一个课程该学生只能参加一次,反之亦然)

然后我们开始创建实体吧。

Student 实体

我们在根目录新建一个“Models”文件夹,创建一个“Student”的类文件,复制以下代码替换掉内容。

  1. using System;
  2. using System.Collections.Generic;
  3. namespace ContosoUniversity.Models
  4. {
  5. public class Student
  6. {
  7. public int ID { get; set; }
  8. public string LastName { get; set; }
  9. public string FirstMidName { get; set; }
  10. public DateTime EnrollmentDate { get; set; }
  11. public ICollection<Enrollment> Enrollments { get; set; }
  12. }
  13. }

Id 属性将作为Student类对应的数据库表的主键,默认情况下EF框架都会将ID或者classnameID作为主键。

Enrollments属性是一个导航属性。

老外翻译太绕了,导航属性就是方便你从一个对象导航到关联对象,也可以用于设置对象之间的关联。

这里Enrollments就是Student实体的导航属性,可以通过Enrollments属性将实体Enrollment和Student中的关联信息获取出来。换句话说:一个学生在数据库中有2行登记信息,(每行包含了Student实体的ID),那么该Student可以从导航属性Enrollments中获取到2行登记信息。

如果一个导航属性包含了多个实体(如:一对多,多对多的关系),那么他们的类型必须一个list类型,可以添加、删除、修改。比如: ICollection<T> 。当然你还可以声明为List<T>或者HashSet<T>.如果你声明为 ICollection<T> .EF会默认创建类型为```HashSet``

Enrollment 实体

同样在Models文件中,创建一个类“Enrollment” 然后把代码替换为如下:

  1. namespace ContosoUniversity.Models
  2. {
  3. public enum Grade
  4. {
  5. A, B, C, D, F
  6. }
  7. public class Enrollment
  8. {
  9. public int EnrollmentID { get; set; }
  10. public int CourseID { get; set; }
  11. public int StudentID { get; set; }
  12. public Grade? Grade { get; set; }
  13. public Course Course { get; set; }
  14. public Student Student { get; set; }
  15. }
  16. }

我们将EnrollmentID作为Enrollment的主键,使用的是classnameID而不是像Student实体中的ID。这里暂时不解释,后面会提到这个问题。

我们声明了一个枚举Grade属性。而在Enrollment实体中Grade是个可空类型,说明他是一个默认可以为空的值,可以在后面根据具体的业务情况来进行赋值处理。

StudentID 作为属性外键,对应的导航属性为Student。ENrollment和Student的关联关系为一对一,所以Enrollment只能持有一个Student实体。(而Student拥有了Enrollment的多个导航属性)

CourseID作为Course的导航属性外键。同样的Enrollment和Course也是一对一的关系。

在这里StudentID作为Student导航属性的外键,等同于Student实体中的ID主键

Course 实体

在Models文件中,创建一个Course类,然后替换为如下代码:

  1. using System.Collections.Generic;
  2. using System.ComponentModel.DataAnnotations.Schema;
  3. namespace ContosoUniversity.Models
  4. {
  5. public class Course
  6. {
  7. [DatabaseGenerated(DatabaseGeneratedOption.None)]
  8. public int CourseID { get; set; }
  9. public string Title { get; set; }
  10. public int Credits { get; set; }
  11. public ICollection<Enrollment> Enrollments { get; set; }
  12. }
  13. }

在这里Enrollments作为导航属性,一个课程会有多个不同学生的登记信息,所以是一对多的关系。

创建数据库上下文(Database Context)

我们需要创建一个作为EF框架用来连接数据库上下文的类。我们创建的类是从System.Data.Entity.DbContext中派生出来的。你可以定义哪些实体包含在EF的数据模型中。你也可以自定义特定的EF行为。在这个项目中,我们创建一个类名“SchoolContext”

  • 在根目录创建一个文件夹“Data”。
  • 在“Data”这个文件夹中,创建一个新的类“SchoolContext”,然后替换代码为下面:
  1. using ContosoUniversity.Models;
  2. using Microsoft.EntityFrameworkCore;
  3. namespace ContosoUniversity.Data
  4. {
  5. public class SchoolContext : DbContext
  6. {
  7. public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
  8. {
  9. }
  10. public DbSet<Course> Courses { get; set; }
  11. public DbSet<Enrollment> Enrollments { get; set; }
  12. public DbSet<Student> Students { get; set; }
  13. }
  14. }

我们为每个实体都创建了一个DbSet的属性。在EF框架中,实体集通常对应数据库中的表,一个实体对应表中的一行数据。

在这里你可以忽略掉**DbSet and DbSet **,它同样会生成表。因为Student会引用Enrollment实体,而Enrollment中包含了Course实体。同样被会引用。EF在生成表的时候会包含他们的引用实体。

创建数据库的时候,数据库的表名会跟 DbSet的属性名一致。属性名称通常会是复数(如 student的表名是Students),但是大多数开发者不同意将表名和实体名字区分开,这样容易混淆。下面的教程就会教会你怎么通过指定你个性化的DbContext表名

把下面的代码,复制到最后的DbSet属性下面

  1. protected override void OnModelCreating(ModelBuilder modelBuilder)
  2. {
  3. modelBuilder.Entity<Course>().ToTable("Course");
  4. modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
  5. modelBuilder.Entity<Student>().ToTable("Student");
  6. }

使用依赖注入的方式来注入DbContext

ASP.NET Core默认实现了依赖注入。在程序启动的时候使用依赖注入将服务(EF的数据库上下文)注入。这些服务的组件(如MVC控制器)通过构造函数的参数实现,下面我们会逐步实现。

首先我们打开“Startup.cs”类,然后将“SchoolContext”注入到ConfigureServices方法中。

  1. services.AddDbContext<SchoolContext>(options =>
  2. options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

连接字符串的名称是通过DbContextOptionsBuilder对象的方法进行上下文调用的。

而在ASP.NET CORE中的连接字符串是通过“appsettings.json”文件实现的。

如下代码:

  1. {
  2. "ConnectionStrings": {
  3. "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
  4. },
  5. "Logging": {
  6. "IncludeScopes": false,
  7. "LogLevel": {
  8. "Default": "Debug",
  9. "System": "Information",
  10. "Microsoft": "Information"
  11. }
  12. }
  13. }

SQL Server Express LocalDB

上面的链接字符串说下吧,连接字符串指定SQL Server LocalDB数据库。LocalDB是一个轻量级版本的SQL Server Express数据库引擎,用于开发环境、而不是生产。LocalDB开始于需求和运行在用户模式下,所以没有复杂的配置。默认情况下,LocalDB创建。

mdf数据库文件在C:/用户/ wer_ltm 文件夹中

我肯定不是这样干的。我们修改下链接字符串

  1. Data Source=.; Database=MaterialCirculation; User ID=sa; Password=123;

初始化数据库并且添加一些测试数据到数据库中

EF框架默认生成的数据库 是一个空数据库,为了我们的测试、开发方便我们添加一些测试数据到数据库中。

这里我们使用EnsureCreated方法来自动创建数据库。在后面的教程中,我们会通过Codefirst迁移的方式来修改数据库而不是传统的删除并重新创建一个数据库的方式来改变模型架构。

在"Data"文件夹中,创建一个“DbInitializer”类,然后把现有代码替换为以下代码:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Microsoft.EntityFrameworkCore;
  5. using Microsoft.Extensions.DependencyInjection;
  6. using ContosoUniversity.Models;
  7. namespace ContosoUniversity.Data
  8. {
  9. public static class DbInitializer
  10. {
  11. public static void Initialize(SchoolContext context)
  12. {
  13. context.Database.EnsureCreated();
  14. // Look for any students.
  15. if (context.Students.Any())
  16. {
  17. return; // DB has been seeded
  18. }
  19. var students = new Student[]
  20. {
  21. new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
  22. new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
  23. new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
  24. new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
  25. new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
  26. new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
  27. new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
  28. new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
  29. };
  30. foreach (Student s in students)
  31. {
  32. context.Students.Add(s);
  33. }
  34. context.SaveChanges();
  35. var courses = new Course[]
  36. {
  37. new Course{CourseID=1050,Title="Chemistry",Credits=3,},
  38. new Course{CourseID=4022,Title="Microeconomics",Credits=3,},
  39. new Course{CourseID=4041,Title="Macroeconomics",Credits=3,},
  40. new Course{CourseID=1045,Title="Calculus",Credits=4,},
  41. new Course{CourseID=3141,Title="Trigonometry",Credits=4,},
  42. new Course{CourseID=2021,Title="Composition",Credits=3,},
  43. new Course{CourseID=2042,Title="Literature",Credits=4,}
  44. };
  45. foreach (Course c in courses)
  46. {
  47. context.Courses.Add(c);
  48. }
  49. context.SaveChanges();
  50. var enrollments = new Enrollment[]
  51. {
  52. new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
  53. new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
  54. new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
  55. new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
  56. new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
  57. new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
  58. new Enrollment{StudentID=3,CourseID=1050},
  59. new Enrollment{StudentID=4,CourseID=1050,},
  60. new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
  61. new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
  62. new Enrollment{StudentID=6,CourseID=1045},
  63. new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
  64. };
  65. foreach (Enrollment e in enrollments)
  66. {
  67. context.Enrollments.Add(e);
  68. }
  69. context.SaveChanges();
  70. }
  71. }}

上面的代码会先检查数据库是否有任何的学生信息,如果没有的话,他会假定数据库需要新的测试种子数据,这里选择了将数据添加到数组中,没有选择List集合来进行性能的优化。

在Startup.cs中,修改Configure 中的方法,以便程序在启动的时候调用Seed方法。

  • 首先修改Configure 方法,添加构造参数"SchoolContext "到方法中,这样ASP.NET 的依赖注入可以提供服务给DbInitializer类。
  1. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, SchoolContext context)
  2. {
  3. loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  4. loggerFactory.AddDebug();

添加代码** DbInitializer.Initialize(context);方法,在整个Configure**方法的最下面。

  1. app.UseMvc(routes =>
  2. {
  3. routes.MapRoute(
  4. name: "default",
  5. template: "{controller=Home}/{action=Index}/{id?}");
  6. });
  7. DbInitializer.Initialize(context);//记得添加这行
  8. }

现在,当你第一次运行程序的时候会给你创建测试数据。每当你更改实体的时候,也就是数据模型的时候,可以删除数据库。更新种子数据并重新创建一个新的数据库。在以后的教程中,你会学会如何通过codefirst的方式通过迁移的方式来进行数据的修改和创建。

创建一个控制器和视图

接下来,我们使用visual studio 中脚手架功能,添加MVC的控制器和视图,将使用EF的查询和保存数据。

通过脚手架功能,我们可以自动创建一个CRUD的功能。你可以通过修改脚手架生成的代码来满足你的业务要求。当你的类发生变化的时候,你可以通过脚手架重新生成代码。

在VS2017 脚手架被叫做了基架 ,在我看来一样的难听。。。

  • 右键选择“Controllers”文件夹,然后选择添加>新搭基建项目

  • 在对话框中,

    • 选择“视图使用EntityFramework的MVC控制器”

      -- 点击添加
  • 添加控制器对话框中

    -- 模型类:选择Student

    -- 数据上下文类:选择 SchoolContext

    -- 接收默认的StudentController作为名称

    -- 点击添加

当你点击“添加的时候”,VS 基架引擎会自动生成一个“StudentController.cs”文件和一组视图文件(.cshtml)。

打开StudentController控制器,你会发现SchoolContext 作为了构造函数的参数。

  1. namespace ContosoUniversity.Controllers
  2. {
  3. public class StudentsController : Controller
  4. {
  5. private readonly SchoolContext _context;
  6. public StudentsController(SchoolContext context)
  7. {
  8. _context = context;
  9. }

我们之前在“Startup.cs”中已经配置了依赖注入。现在

ASP.NET会通过依赖注入的方式,将SchoolContext 注入到控制器中。

控制器中包含了一个Index的Action 方法,它会将数据库中的所有学生信息都显示出来。

await _context.Students.ToListAsync() 方法会从Student实体通过读取数据库上下文属性获取学生列表。

  1. public async Task<IActionResult> Index()
  2. {
  3. return View(await _context.Students.ToListAsync());
  4. }

这里是采用了异步方法。我们在后面讲解

我们先打开“Views/Students/Index.cshtml ”视图文件:

  1. @model IEnumerable<ContosoUniversity.Models.Student>
  2. @{
  3. ViewData["Title"] = "Index";
  4. }
  5. <h2>Index</h2>
  6. <p>
  7. <a asp-action="Create">Create New</a>
  8. </p>
  9. <table class="table">
  10. <thead>
  11. <tr>
  12. <th>
  13. @Html.DisplayNameFor(model => model.LastName)
  14. </th>
  15. <th>
  16. @Html.DisplayNameFor(model => model.FirstMidName)
  17. </th>
  18. <th>
  19. @Html.DisplayNameFor(model => model.EnrollmentDate)
  20. </th>
  21. <th></th>
  22. </tr>
  23. </thead>
  24. <tbody>
  25. @foreach (var item in Model) {
  26. <tr>
  27. <td>
  28. @Html.DisplayFor(modelItem => item.LastName)
  29. </td>
  30. <td>
  31. @Html.DisplayFor(modelItem => item.FirstMidName)
  32. </td>
  33. <td>
  34. @Html.DisplayFor(modelItem => item.EnrollmentDate)
  35. </td>
  36. <td>
  37. <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
  38. <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
  39. <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
  40. </td>
  41. </tr>
  42. }
  43. </tbody>
  44. </table>

好了 按 CTRL + F5 运行项目或选择调试 > 开始执行(不调试)。

在菜单上选择Student按钮。然后就可以看到我们的数据信息。

查看数据库

如果你是改了连接字符串的话,直接打开数据库看表吧。如果你没有更改,那就不要跳过这里了。

我们刚刚说过了,你如果采用的是免费版本的话,现在要查看数据库就需要打开

工具-连接数据库

展开表信息,然后选择Student 然后右键表,点击查看数据。

公约

由于EF框架的公约/设定,为了让EntityFramework能够为您创建一个完整的数据库,你只需要编写很少的代码。

  • DbSet 属性的名称作为表的名称。对于不是由DbSet属性引用的实体,实体类名将作为表的名称
  • 实体属性名称会作为表的列名称
  • 名为ID或者classnameID的实体属性会被识别为主键属性
  • 如果属性被命名,属性则会被EF作为外键属性。(例如:StudentID对于Student导航属性,因为Student实体的主键为ID)。外键属性也可以随意命名。(例如:EnrollmentID因为Enrollment实体的主键是EnrollmentID)

一些常规的设定是可以进行覆盖的。例如你可以显示指定表的名称,就如我们之前做的,自定义表的名称。

当然你也可以设置列名称并将任何属性设置为主键或者外键。在后面的教程中我们会涉及。

关于异步代码

异步编程是ASP.NET Core和EF Core的默认模式。

Web服务器的线程数量是有限的,在高负载的情况下,可能所有的线程都被占用了。当发生这种情况的时候,服务器不能处理新的请求,直到线程被释放出来。再以前使用同步代码请求,许多线程可能被绑定,他们实际上没有做任何工作,因为他们正在等待I/O完成。使用异步写代码,当进程等待I/O完成的时候,它的线程就会被释放,服务器用于处理其他请求。因此,异步代码使服务器资源能够更有效地使用,并且服务器能够无延迟地处理更多流量。

异步代码在运行时引入少量开销,但是对于低流量情况,性能命中是可以忽略的,而对于高流量情况,潜在的性能改进是巨大的。

在以下代码中,async关键字,Task返回值,await关键字和ToListAsync方法使代码异步执行。

  1. public async Task<IActionResult> Index()
  2. {
  3. return View(await _context.Students.ToListAsync());
  4. }
  • 该async关键字告诉编译器生成方法不会回调和自动创建Task返回的对象。
  • 返回类型Task表示正在进行的工作与类型的结果IActionResult。
  • 该await关键字使编译器将该方法拆分为两部分。第一部分以异步启动的操作结束。第二部分被放入一个在操作完成时被调用的回调方法中。
  • ToListAsync是ToList扩展方法的异步版本。

当你使用EntityFramework的异步代码的时候,你需要注意一些事情:

  • 只有查询或者发送命令到数据库的时候才能使用异步语句。如:ToListAsync,SingleOrDefaultAsync,和SaveChangesAsync。不包含 类型为IQueryable,修改命令。比如
  1. var students = context.Students.Where(s => s.LastName == "Davolio").
  • EF的上下文不是线程安全的:不要尝试执行/并行多个操作。当您调用任何异步EF方法的时候,始终使用“await”关键字。

  • 如果你想使用异步的性能优势,请确保你使用的任何包(例如分页),他们调用的Entity Framework 方法,使用async发送到数据库中。

基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-2的更多相关文章

  1. 基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-1

    来个目录吧: 第一章 第二章 第三章 暂时就这么多.后面路线更新吧 本系列文章为翻译加上我个人的使用心得理解,希望帮助热爱学习的程序员. 珍重声明:本系列文章会跟原文有点出入,去掉了罗里吧嗦的文字. ...

  2. 基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-4

    来个目录吧: 第一章-入门 第二章- Entity Framework Core Nuget包管理 第三章-创建.修改.删除.查询 第四章-排序.过滤.分页.分组 第五章-迁移,EF Core 的co ...

  3. 基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-3

    来个目录吧: 第一章 第二章 第三章 暂时就这么多.后面路线更新吧 创建.查询.更新.删除 这章主要讲解使用EF完成 增删改查的功能. 自定义"详情信息"页面 我们通过基架生成的代 ...

  4. 基于Asp.Net Core Mvc和EntityFramework Core 的实战入门教程系列-5

    来个目录吧: 第一章-入门 第二章- Entity Framework Core Nuget包管理 第三章-创建.修改.删除.查询 第四章-排序.过滤.分页.分组 第五章-迁移,EF Core 的co ...

  5. 基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术-Angel工作室通用权限管理

    一.Angel工作室简单通用权限系统简介 AngelRM(Asp.net MVC Web api)是基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术 ...

  6. 基于ASP.NET的MVC框架下的MvcPaper分页控件的使用技术

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using Webdiyer. ...

  7. 基于Asp.Net Core 2.1的简单问答社区系统源代码分享

    看见园子里很多人都在分享源代码,我也来凑个热闹. 该项目基于.NET CORE 2.1(其实是从1.1开始开发的),经历过不停的调整终于有个能拿出手的版本了,第一次在博客园发文章. 使用到的技术以及框 ...

  8. ASP.NET Core 入门教程 6、ASP.NET Core MVC 视图布局入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)视图母版页教程 ASP.NET Core MVC (Razor)带有Section的视图母版页教程 ASP.NET Cor ...

  9. ASP.NET Core 入门笔记7,ASP.NET Core MVC 视图布局入门

    一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)视图母版页教程 ASP.NET Core MVC (Razor)带有Section的视图母版页教程 ASP.NET Cor ...

随机推荐

  1. iOS 项目上线流程

    一.证书的导出      1.1 前期工作        首先你需要有一个苹果的开发者帐号,一个Mac系统.        如果没有帐号可以在打开http://developer.apple.com/ ...

  2. QT第二天学习

    回顾: qmake: qmake -project //生成*.pro文件 qmake //makefile make 注:if(qmake -v  >=5) then QT += widget ...

  3. Bootstrap3网上api文档地址

    http://v3.bootcss.com/css/#forms http://www.ziqiangxuetang.com/bootstrap/bootstrap-forms.html 另附加fa字 ...

  4. VMware虚拟机与宿主无法复制的解决办法

    由于工作需要,上网机器使用虚拟机,因此需要经常来回的拷贝文件,而vmware从6.5一直走来到10.0.1,总是有一个问题很让人苦恼---共享粘贴板总是会无故失效.经常实验,发现可以经过以下方法临时解 ...

  5. 我为什么不看好微信小程序

    我自认为对新技术还是比较有热情的,可对于小程序这个“新技术”,我却完全是被动的.去年9月份的时候,微信小程序开始内测,瞬间引爆朋友圈.知乎等一众分享平台.当时我大概了解了一下,觉得从技术角度上来说没啥 ...

  6. 数据流程redux学习(一)

    思考题: react+redux开发这么一个原型,要怎么开发? 整个redux流程的逻辑非常清晰,数据流是单向循环的,就像一个生产的流水线: store(存放状态) -> Container(显 ...

  7. MD5碰撞后时代,MD5还有存在的意义吗?

    MD5是一种HASH函数,又称杂凑函数,由32位16进制组成,在信息安全范畴有广泛和首要运用的暗码算法,它有类似于指纹的运用.在网络安全协议中, 杂凑函数用来处理电子签名,将冗长的签名文件紧缩为一段一 ...

  8. 只为粗暴看一下ES6的字符串模板的性能

    网上查找"ES6 字符串模板 +性能"5分钟无果遂写了一个暴力测试. 测试对象: +=方式,字符串累加计算方式 +s1+s2...+sn方式,即传统连加拼接字符串方式 s.push ...

  9. Program terminated with signal SIGKILL,Killed

    车载后视镜机器,Liinux + qtUI形式,前后双路,前一天晚上开机用gdb run DvrUI,第二天早上回来一看,机器绿屏卡死了,录像预览停止刷新了,sd录像也停止了.点击无任何反应. 看gd ...

  10. 微端游戏启动器launcher的制作之下载篇(系列一)

    首先第一篇先讲一讲launcher最核心的功能---下载功能. 这个部分估计得好几篇才能写完,东西比较多也比较杂,慢慢来吧,我的东西也在继续改进中...... 从web上下载文件需要用到几个类,Htt ...