用ASP.NET Core MVC 和 EF Core 构建Web应用 (一)

系统必备

  • .NET Core 2.0.0 SDK 或更高版本。
  • 已安装 ASP.NET 和 Web 开发工作负载的 Visual Studio 2017 15.3 版或更高版本。

创建Web应用程序

打开 Visual Studio 并创建一个新 ASP.NET Core C# web 项目名为”ContosoUniversity”。

  • 文件菜单上,选择新建 > 项目

  • 从左窗格中,选择已安装 > Visual C# > Web

  • 选择“ASP.NET Core Web 应用程序”项目模板。

  • 输入ContosoUniversity作为名称,然后单击确定

  • 在 “新建 ASP.NET Core Web 应用程序” 对话框,选择ASP.NET Core 2.1和 Web 应用程序 (模型-视图-控制器)模板。

  • 注意:本教程需要安装 ASP.NET Core 2.0 和 EF Core 2.0 或更高版本。

  • 请确保身份验证设置为不进行身份验,单击“确定”。

 

修改页面菜单布局和主页

打开Views/Shared/_Layout.cshtml并进行以下更改:

  • 将文件中的”ContosoUniversity”更改为”Contoso University”。 需要更改三个地方。

  • 添加菜单项StudentsCoursesInstructors,和Department,并删除Contact菜单项。

1 <li><a asp-area="" asp-controller="Students" asp-action="Index">Students</a></li>
2 <li><a asp-area="" asp-controller="Courses" asp-action="Index">Courses</a></li>
3 <li><a asp-area="" asp-controller="Instructors" asp-action="Index">Instructors</a></li>
4 <li><a asp-area="" asp-controller="Departments" asp-action="Index">Departments</a></li>

Views/Home/Index.cshtml,将文件的内容替换为以下代码以将有关 ASP.NET 和 MVC 的内容替换为有关此应用程序的内容:

@{ViewData["Title"] = "Home Page";
}<div class="jumbotron"><h1>Contoso University</h1>
</div>
<div class="row"><div class="col-md-4"><h2>Welcome to Contoso University</h2><p>Contoso University is a sample application thatdemonstrates how to use Entity Framework Core in anASP.NET Core MVC web application.</p></div><div class="col-md-4"><h2>Build it from scratch</h2><p>You can build the application by following the steps in a series of tutorials.</p><p><a class="btn btn-default" href="https://docs.asp.net/en/latest/data/ef-mvc/intro.html">See the tutorial &raquo;</a></p></div><div class="col-md-4"><h2>Download it</h2><p>You can download the completed project from GitHub.</p><p><a class="btn btn-default" href="https://github.com/aspnet/Docs/tree/master/aspnetcore/data/ef-mvc/intro/samples/cu-final">See project source code &raquo;</a></p></div>
</div>
View Code

CTRL + F5 来运行该项目或从菜单选择调试 > 开始执行不调试。 你会看到首页和将通过这个教程创建的页对应的选项卡。

 

数据访问部分使用 EF Core

若要为项目添加 EF Core 支持,需要安装相应的数据库驱动包。 本教程使用 SQL Server,相关驱动包Microsoft.EntityFrameworkCore.SqlServer。 该包包含在Microsoft.AspNetCore.All 包中,因此不需要手动安装。此包和其依赖项 (Microsoft.EntityFrameworkCoreMicrosoft.EntityFrameworkCore.Relational) 一起提供 EF 的运行时支持。 

创建数据模型

创建 Contoso 大学应用程序的实体类,从以下三个实体类开始。

 

StudentEnrollment实体之间是一对多的关系,CourseEnrollment实体之间也是一个对多的关系。 换而言之,一名学生可以修读任意数量的课程, 并且某一课程可以被任意数量的学生修读。

Models文件夹中,创建一个名为Student.cs的类文件并且将模板代码替换为以下代码。

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

ID属性将成为对应于此类的数据库表中的主键。 默认情况下,EF 将会将名为IDclassnameID的属性解析为主键。

Enrollments属性是导航属性。 导航属性中包含与此实体相关的其他实体。 在这个案例下,Student entity中的Enrollments属性会保留所有与Student实体相关的Enrollment。 换而言之,如果在数据库中有两行描述同一个学生的修读情况 (两行的 StudentID 值相同,而且 StudentID 作为外键和某位学生的主键值相同),Student实体的Enrollments导航属性将包含那两个Enrollment实体。

如果导航属性可以具有多个实体 (如多对多或一对多关系),那么导航属性的类型必须是可以添加、 删除和更新条目的容器,如ICollection<T>。 你可以指定ICollection<T>或实现该接口类型,如List<T>HashSet<T>。 如果指定ICollection<T>,EF在默认情况下创建HashSet<T>集合。

Models文件夹中,创建Enrollment.cs并且用以下代码替换现有代码:

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

EnrollmentID属性将被设为主键; 此实体使用classnameID模式而不是如Student实体那样直接使用ID。 通常情况下,你选择一个主键模式,并在你的数据模型自始至终使用这种模式。 在这里,使用了两种不同的模式只是为了说明你可以使用任一模式来指定主键。 

Grade属性是enum。 Grade声明类型后的?表示Grade属性可以为 null。 评级为 null 和评级为零是有区别的 –null 意味着评级未知或者尚未分配。

StudentID属性是一个外键,Student是与其且对应的导航属性。 Enrollment实体与一个Student实体相关联,因此该属性只包含单个Student实体 (与前面所看到的Student.Enrollments导航属性不同后,Student中可以容纳多个Enrollment实体)。

CourseID属性是一个外键,Course是与其对应的导航属性。 Enrollment实体与一个Course实体相关联。

如果一个属性名为<导航属性名><主键属性名>,Entity Framework 就会将这个属性解析为外键属性(例如,Student实体的主键是IDStudentEnrollment的导航属性所以Enrollment实体中StudentID会被解析为外键)。 此外还可以将需要解析为外键的属性命名为<主键属性名>(例如,CourseID由于Course实体的主键所以CourseID也被解析为外键)。

Models文件夹中,创建Course.cs并且用以下代码替换现有代码:

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

Enrollments属性是导航属性。 一个Course实体可以与任意数量的Enrollment实体相关。

 

创建数据库上下文

使得给定的数据模型与 Entity Framework 功能相协调的主类是数据库上下文类。 可以通过继承 Microsoft.EntityFrameworkCore.DbContext 类的方式创建此类。 在该类中你可以指定数据模型中包含哪些实体。 你还可以定义某些 Entity Framework 行为。 在此项目中将数据库上下文类命名为SchoolContext

在项目文件夹中,创建名为的文件夹Data。在Data文件夹创建名为SchoolContext.cs的类文件,并将模板代码替换为以下代码:

 1 using ContosoUniversity.Models;
 2 using Microsoft.EntityFrameworkCore;
 3 
 4 namespace ContosoUniversity.Data
 5 {
 6     public class SchoolContext : DbContext
 7     {
 8         public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
 9         {
10         }
11 
12         public DbSet<Course> Courses { get; set; }
13         public DbSet<Enrollment> Enrollments { get; set; }
14         public DbSet<Student> Students { get; set; }
15     }
16 }
View Code

此代码将为每个实体集创建DbSet属性。 在 Entity Framework 中,实体集通常与数据表相对应,具体实体与表中的行相对应。

在这里可以省略DbSet<Enrollment>DbSet<Course>语句,实现的功能没有任何改变。 Entity Framework 会隐式包含这两个实体因为Student实体引用了Enrollment实体、Enrollment实体引用了Course实体。

当数据库创建完成后, EF 创建一系列数据表,表名默认和DbSet属性名相同。 集合属性的名称一般使用复数形式,但不同的开发人员的命名习惯可能不一样,开发人员根据自己的情况确定是否使用复数形式。在最后一个 DbSet 属性之后添加以下代码,对 DbContext 指定单数的表明来覆盖默认的表名。

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         }
View Code

 

用依赖注入注册上下文

ASP.NET Core 默认实现依赖注入。在应用程序启动过程通过依赖注入注册相关服务 (例如 EF 数据库上下文)。 需要这些服务的组件 (如 MVC 控制器) 可以通过向构造函数添加相关参数来获得对应服务。

若要将SchoolContext注册为一种服务,打开Startup.cs,并将以下代码添加到ConfigureServices方法中。

1 public void ConfigureServices(IServiceCollection services)
2 {
3     services.AddDbContext<SchoolContext>(options =>
4         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
5 
6     services.AddMvc();
7 }
View Code

通过调用DbContextOptionsBuilder中的一个方法将数据库连接字符串在配置文件中的名称传递给上下文对象。 进行本地开发时, ASP.NET Core 配置系统在appsettings.json文件中读取数据库连接字符串。

添加using语句引用ContosoUniversity.DataMicrosoft.EntityFrameworkCore命名空间,然后生成项目。

打开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": "Warning"
 9     }
10   }
11 }

数据库连接字符串指定使用 SQL Server LocalDB 数据库。 LocalDB 是 SQL Server Express 数据库引擎的轻量级版本,用于应用程序开发,不在生产环境中使用。 LocalDB 作为按需启动并在用户模式下运行的轻量级数据库没有复杂的配置。 默认情况下, LocalDB 在C:/Users/<user>目录下创建.mdf数据库文件。

用测试数据初始化数据库

Entity Framework 已经为你创建了一个空数据库。在本部分中编写一个方法用于向数据库填充测试数据,该方法会在数据库创建完成之后执行。

此处将使用EnsureCreated方法来自动创建数据库。 在Data文件夹中,创建名为的新类文件DbInitializer.cs并且将模板代码替换为以下代码,使得在需要时能创建数据库并向其填充测试数据。

 1 using ContosoUniversity.Models;
 2 using System;
 3 using System.Linq;
 4 
 5 namespace ContosoUniversity.Data
 6 {
 7     public static class DbInitializer
 8     {
 9         public static void Initialize(SchoolContext context)
10         {
11             context.Database.EnsureCreated();
12 
13             // Look for any students.
14             if (context.Students.Any())
15             {
16                 return;   // DB has been seeded
17             }
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 
36             var courses = new Course[]
37             {
38             new Course{CourseID=1050,Title="Chemistry",Credits=3},
39             new Course{CourseID=4022,Title="Microeconomics",Credits=3},
40             new Course{CourseID=4041,Title="Macroeconomics",Credits=3},
41             new Course{CourseID=1045,Title="Calculus",Credits=4},
42             new Course{CourseID=3141,Title="Trigonometry",Credits=4},
43             new Course{CourseID=2021,Title="Composition",Credits=3},
44             new Course{CourseID=2042,Title="Literature",Credits=4}
45             };
46             foreach (Course c in courses)
47             {
48                 context.Courses.Add(c);
49             }
50             context.SaveChanges();
51 
52             var enrollments = new Enrollment[]
53             {
54             new Enrollment{StudentID=1,CourseID=1050,Grade=Grade.A},
55             new Enrollment{StudentID=1,CourseID=4022,Grade=Grade.C},
56             new Enrollment{StudentID=1,CourseID=4041,Grade=Grade.B},
57             new Enrollment{StudentID=2,CourseID=1045,Grade=Grade.B},
58             new Enrollment{StudentID=2,CourseID=3141,Grade=Grade.F},
59             new Enrollment{StudentID=2,CourseID=2021,Grade=Grade.F},
60             new Enrollment{StudentID=3,CourseID=1050},
61             new Enrollment{StudentID=4,CourseID=1050},
62             new Enrollment{StudentID=4,CourseID=4022,Grade=Grade.F},
63             new Enrollment{StudentID=5,CourseID=4041,Grade=Grade.C},
64             new Enrollment{StudentID=6,CourseID=1045},
65             new Enrollment{StudentID=7,CourseID=3141,Grade=Grade.A},
66             };
67             foreach (Enrollment e in enrollments)
68             {
69                 context.Enrollments.Add(e);
70             }
71             context.SaveChanges();
72         }
73     }
74 }
View Code

这段代码首先检查是否有学生数据在数据库中,如果没有的话,就可以假定数据库是新建的,然后使用测试数据进行填充。代码中使用数组存放测试数据而不是使用List<T>集合是为了优化性能。

Program.cs,修改Main方法,使得在应用程序启动时能执行以下操作:

  • 从依赖注入容器中获取数据库上下文实例。
  • 调用 seed 方法,将上下文传递给它。
  • Seed 方法完成此操作时释放上下文。
 1 using ContosoUniversity.Data;
 2 using Microsoft.AspNetCore;
 3 using Microsoft.AspNetCore.Hosting;
 4 using Microsoft.Extensions.DependencyInjection;
 5 using Microsoft.Extensions.Logging;
 6 using System;
 7 
 8 namespace ContosoUniversity
 9 {
10     public class Program
11     {
12         public static void Main(string[] args)
13         {
14             var host = CreateWebHostBuilder(args).Build();
15             using (var scope = host.Services.CreateScope())
16             {
17                 var services = scope.ServiceProvider;
18                 try
19                 {
20                     var context = services.GetRequiredService<SchoolContext>();
21                     DbInitializer.Initialize(context);
22                 }
23                 catch (Exception ex)
24                 {
25                     var logger = services.GetRequiredService<ILogger<Program>>();
26                     logger.LogError(ex, "An error occurred while seeding the database.");
27                 }
28             }
29             host.Run();
30         }
31 
32         public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
33             WebHost.CreateDefaultBuilder(args)
34                 .UseStartup<Startup>();
35     }
36 }
View Code

现在首次运行该应用程序,创建数据库并使用测试数据作为种子数据。 每当你更改你的数据模型,你可以删除数据库、 更新你的 Initialize 方法,然后使用上述方式更新新数据库。 在之后的教程中,你将了解如何在数据模型更改时,只需修改数据库而无需删除重建数据库。

创建控制器和视图

用 Visual Studio 中的基架引擎添加一个 MVC 控制器和使用 EF 来查询和保存数据的视图。

CRUD 操作方法和视图的自动创建被称为基架。 基架与代码生成不同,基架的代码是一个起点,您可以修改基架以满足自己需求,而你通常无需修改生成的代码。 当你需要自定义生成代码时,你使用一部分类或需求发生变化时重新生成代码。

  • 右键单击解决方案资源管理器中的Controllers文件夹选择添加 > 新搭建的基架项目
  • 在添加基架的对话框中:

    • 选择视图使用 Entity Framework 的 MVC 控制器

    • 单击添加

  • 在添加控制器对话框中:

    • 在模型类选择Student

    • 在数据上下文类选择SchoolContext

    • 使用StudentsController作为默认名字

    • 单击添加

 

  • 当你单击添加后,Visual Studio 基架引擎创建StudentsController.cs文件和一组对应于控制器的视图 (.cshtml文件) 。

(如果你之前手动创建数据库上下文,基架引擎还可以自动创建。 你可以在添加控制器对话框中单击右侧的加号框数据上下文类来指定在一个新上下文类。然后,Visual Studio 将创建你的DbContext,控制器和视图类。)

你会注意到控制器采用SchoolContext作为构造函数参数。

    public class StudentsController : Controller{private readonly SchoolContext _context;public StudentsController(SchoolContext context){_context = context;}

ASP.NET 依赖注入机制将会处理传递一个SchoolContext实例到控制器。

控制器包含Index操作方法用于显示数据库中的所有学生。 该方法从学生实体集中获取学生列表,学生实体集则是通过读取数据库上下文实例中的Students属性获得:

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

Views/Students/Index.cshtml视图使用table标签显示此列表:

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

按 CTRL + F5 来运行该项目或从菜单选择调试 > 开始执行(不调试)。

单击学生选项卡以查看DbInitializer.Initialize插入的测试的数据。 你将看到Student选项卡链接在页的顶部或在单击右上角后的导航图标中,具体显示在哪里取决于浏览器窗口宽度。

    

 

约定

由于 Entity Framwork 有一定的约束条件,你只需要按规则编写很少的代码就能够创建一个完整的数据库,

  • DbSet类型的属性用作表名。 实体未被DbSet属性引用,实体类名称用作表名称。

  • 实体属性名称用于列名称。

  • ID 或 classnameID 命名的实体属性被识别为主键属性。

  • 如果属性名为 <导航属性名> <主键名>将被解释为外键属性 (例如,StudentID对应Student导航属性,Student实体的主键是ID,所以StudentID被解释为外键属性). 此外也可以将外键属性命名为 <主键属性名> (例如,EnrollmentID,由于Enrollment实体的主键是EnrollmentID,因此被解释为外键)。

约定行为可以被重写。 例如,设置列名称和将任何属性设置为主键或外键。

异步代码

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

Web 服务器的可用线程是有限的,而在高负载情况下的可能所有线程都被占用。 当发生这种情况的时候,服务器就无法处理新请求,直到线程被释放。 使用同步代码时,可能会出现多个线程被占用但不能执行任何操作的情况,因为它们正在等待 I/O 完成。 使用异步代码时,当进程正在等待 I/O 完成,服务器可以将其线程释放用于处理其他请求。 因此,异步代码使得服务器更有效地使用资源,并且该服务器可以无延迟地处理更多流量。

异步代码在运行时,会引入的少量开销,在低流量时对性能的影响可以忽略不计,但在针对高流量情况下潜在的性能提升是可观的。

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

public async Task<IActionResult> Index()
{return View(await _context.Students.ToListAsync());
}
  • async关键字用于告知编译器该方法主体将生成回调并自动创建Task<IActionResult>返回对象。

  • 返回类型Task<IActionResult>表示正在进行的工作返回的结果为IActionResult类型。

  • await关键字会使得编译器将方法拆分为两个部分。 第一部分是以异步方式结束已启动的操作。 第二部分是当操作完成时注入调用回调方法的地方。

  • ToListAsync是由ToList方法的的异步扩展版本。

你使用 Entity Framework 编写异步代码时的一些注意事项:

  • 只有导致查询或发送数据库命令的语句才能以异步方式执行。 包括 ToListAsync, SingleOrDefaultAsync,和SaveChangesAsync。 不包括,操作IQueryable的语句,如var students = context.Students.Where(s => s.LastName == "Lilo")

  • EF 上下文是线程不安全的: 请勿尝试并行执行多个操作。 当调用异步 EF 方法时,始终使用await关键字。

  • 如果你想要利用异步代码的性能优势,请确保你所使用的任何库和包在它们调用导致 Entity Framework 数据库查询方法时也使用异步。 

总结

现已创建了一个使用 Entity Framework Core 和 SQL Server Express LocalDB 来存储和显示数据的简单应用程序。 在下一篇中,将介绍如何执行基本的 CRUD (创建、 读取、 更新、 删除) 操作。

 

 

 

 

 *****************************
 *** Keep learning and growing. ***
 *****************************

转载于:https://www.cnblogs.com/gangle/p/9190287.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/266881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一个Django应用程序_part1

一、查看Django是否安装 参考文档&#xff1a;https://docs.djangoproject.com/en/1.11/intro/tutorial01/ 如果Django已经安装&#xff0c;可以看到安装的版本号&#xff0c;如果没有安装则会看到“No module named django”的错误。 MacBook-Pro:~ h$ python3 -m django --ve…

HTML 文档流和文本流的理解

文本流&#xff0c;概括地说其实就是一系列字符&#xff0c;是文档的读取和输出顺序&#xff0c;也就是我们通常看到的由左到右、由上而下的读取和输出形式&#xff0c;在网页中每个元素都是按照这个顺序进行排序和显示的&#xff0c;而position属性可以将元素从文本流脱离出来…

CCNA实验(一)

无线局域网&#xff08;WLAN&#xff09;回顾 使用无线射频信号、载波监听多路访问/冲突避免、半双工。 无线AP相当于以太网的HUB。 有些频段是受限的。 无线信号遇到的问题&#xff1a; l 反射 l 散射 l 信号吸收&#xff08;比如说穿墙&#xff09; 无线标准 l ITU-R l …

linux中postfix(基于源码)的邮件系统

一、安装前的准备工作&#xff1a; 首先配置yum服务器&#xff0c;安装dns 1、安装所需的rpm包&#xff0c;这包括以下这些&#xff1a; httpd, php, php-mysql, mysql, mysql-server, mysql-devel, openssl-devel, dovecot, perl-DBD-MySQL, tcl, tcl-devel, libart_lgpl, li…

UE4 集成讯飞听写插件

搞了几天&#xff0c;有些坑记录一下。 3个方面的知识需要学习 1、制作UE4插件 2、引入第三方库 3、讯飞听写的api 一看是参考 https://blog.csdn.net/u012793104/article/details/78067937 http://doc.xfyun.cn/msc_windows/%E8%AF%AD%E9%9F%B3%E5%90%AC%E5%86%99.html API&am…

c51单片机有几个终端语言,吃过大亏,才知道要从51单片机入手

原标题&#xff1a;吃过大亏&#xff0c;才知道要从51单片机入手在这里&#xff0c;我就不说什么是单片机了&#xff0c;而是说说怎样学单片机&#xff0c;就我个人而言先学51,因为这个单片机在中国市场上发展了几十年了&#xff0c;现在工程中用的比较多的也是MCS-51, 它的资料…

医疗项目中对网编的一些理解看法

医疗项目中对网编的一些理解看法。做网络营销都有一个前提&#xff0c;那就是以用户为中心&#xff0c;站在用户的角度考 虑问题。在网络营销中&#xff0c;网编如何提升充实自己&#xff1f;怎么获得信息渠道&#xff1f;见多&#xff1a;多看&#xff0c;多了解行业的变化&am…

android 自定义view画表格,Android自定义View实现课程表表格

自己闲下来时间写的一个课表控件&#xff0c;使用的自定义LinearLayout&#xff0c;里面View都是用代码实现的&#xff0c;最终效果如下图&#xff0c;写的可能有问题希望多多指点创建一个自定义LinearLayout 控件用来装载课程的信息和课程的周数&#xff0c;和节数大概的布局三…

26.中继器数据的添加与删除

选择中继器里面的数据集再选择增加行 勾上之后选择下方的增加行就可以填入数据了 用变量获取用户输入的各项内容 但是图片不能用公式操作 方法&#xff1a;通过右键单击图片获得图片的地址 图片中蓝色的部分就是相对路径 把这个路径放到中继器的数据里就可以用了 以上是添加&am…

android工作机制和内核,android内核剖析学习笔记:AMS(ActivityManagerService)内部原理和工作机制...

一、ActivityManagerService提供的主要功能&#xff1a;(1)统一调度各应用程序的Activity(2)内存管理(3)进程管理二、启动一个Activity的方式有以下几种&#xff1a;(1)在应用程序中调用startActivity启动指定的Activity(2)在Home程序中单击一个应用图标&#xff0c;启动新的Ac…

从.Net到Java学习第四篇——spring boot+redis

从.Net到Java学习系列目录 “学习java已经十天&#xff0c;有时也怀念当初.net的经典&#xff0c;让这语言将你我相连&#xff0c;怀念你......”接上一篇&#xff0c;本篇使用到的框架redis、FastJSON。 环境准备 安装redis&#xff0c;下图是我本机的redis绿色版&#xff0c;…

hdu 4409 Family Name List LCA +stl

http://acm.hdu.edu.cn/showproblem.php?pid4409 赛后才过只能说悲剧了&#xff0c;知道思路&#xff0c;stl不熟悉&#xff0c;所以导致写的很慢....占据了很多时间&#xff0c;手速代码准确度。。哎。。。 题意&#xff1a; 给你一个家谱&#xff0c;n个人的姓名&#xff0c…

mysql杂记

1、 mysql安装完成后需要将mysql里面的bin目录加到环境变量里之后&#xff0c;才能在cmd窗口里使用mysql命令 2、 在CMD命令窗口敲入命令 mysql -hlocalhost -uroot -ppassword进入mysql数据库 这里我的用户名是root&#xff0c;密码是123456 转载于:https://www.cnblogs.com/y…

vue created 生命周期

在实例创建完成后被立即调用。在这一步&#xff0c;实例已完成以下的配置&#xff1a;数据观测 (data observer)&#xff0c;属性和方法的运算&#xff0c;watch/event 事件回调。然而&#xff0c;挂载阶段还没开始&#xff0c;$el属性目前不可见。 methods、data、watch等可以…

android cne服务,Android内存优化-了解内存篇

查看系统内存文件shellaries:/ $ cat /proc/meminfoMemTotal: 1970216 kBMemFree: 83756 kBBuffers: 156020 kBCached: 702516 kBSwapCached: 0 kBActive: 1160284 kBInactive: 397932 kBActive(anon): 778932 kBInactive(anon): 2228 kBActive(file): 381352 kBInactive(file)…

Shell中的特殊字符

通配符 当需要用命令处理一组文件&#xff0c;例如file1.txt、file2.txt、file3.txt……&#xff0c;用 户不必一一输入文件名&#xff0c;可以使用Shell通配符。Shell命令的通配符含义如下表 引号 在 Shell 中引号分为 2 种&#xff1a;单引号、双引号。 &#xff08; 1 &…

android的帧布局,七、Android帧布局FrameLayout和霓虹灯效果

帧布局容器为每个加入其中的组件创建一个空白的区域(称为一帧)&#xff0c;所有每个子组件占据一帧&#xff0c;这些帧都会根据gravity属性执行自动对齐。FrameLayout的常用XML属性和相关方法XML属性相关方法说  明android:foregroundsetForeground(Drawable)设置该帧布局容器…

flutter能开发游戏吗_Steam上架游戏开发软件,不用代码也能制作游戏,而且还是免费的...

时代在变化&#xff0c;科技在进步&#xff0c;曾几何时我们一度以为的高科技&#xff0c;在现在看来也不过是平常到不能再平常的东西。游戏开发也一样&#xff0c;以前需要代码才能开发制作而成&#xff0c;现如今都不需要了&#xff0c;直接编辑就OK&#xff0c;Steam商城这次…

快速构建Windows 8风格应用10-设备方向

本篇博文主要介绍常用支持Windows 8操作系统设备的方向、如何获取当前设备方向、DisplayProperties类 常用支持Windows 8操作系统设备的方向在我们常用的设备当中&#xff0c;Windows 8是通过什么来监控设备方向呢&#xff1f;答案是方向传感器&#xff0c;那么对于设备的不同方…

CSDN怎么转载别人的博客

参考&#xff1a;CSDN怎么转载别人的博客 作者&#xff1a;zhongjianblackberry 发布时间&#xff1a;2018-03-06 11:57:59 网址&#xff1a;https://blog.csdn.net/zhongjianblackberry/article/details/79456338 目录转载CSDN博客步骤&#xff1a;Markdown和HTML相关小知识Ma…