首先新建好专案後
一样记得要先弄好MVC服务注入跟MVC预设路由形式设定
(可参考.NET Core第8天_路由端点的切换_注入MVC服务_利用middleware来启用静态资源设置预设网址路由)
新增好空的.net core专案後
到nuget中安装entityframework core相关套件
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
在PMC (Package Manager Console) 下Scaffold-DbContext指令
将建立既有资料库的 EF Core 模型。
「Tools」 - 「NuGet Package Manager」 - 「Package Manager Console」,输入以下指令:
Scaffold-DbContext "Server=.\SQLExpress;Database=Northwind;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Employees,Orders
指令完整的格式定义
Scaffold-DbContext "Server=服务器位置;Database=资料库;Trusted_Connection=True;MultipleActiveResultSets=true;User ID=帐号;Password=密码" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Force
北风资料库若本机SSMS还没有可以自己新建
https://github.com/microsoft/sql-server-samples/tree/master/samples/databases/northwind-pubs
"Server=.\SQLExpress;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=true"
将连接到本机SqlExpress服务器里头的Northwind资料库
Trusted_Connection=True
信任目前登入帐号登入资料库。
MultipleActiveResultSets=true
允许在单一次DB连线中可执行多个批次作业。
-OutputDir Models
代表要将自动产生的档案放入到 /Models之下
否则预设会统一放在专案跟目录就容易零乱
此时若一执行会报错
Scaffold-DbContext : 无法辨识 'Scaffold-DbContext' 词汇是否为 Cmdlet、函数、指令档或可执行程序的名称。
这里要再补安装一个nuget套件
Microsoft.EntityFrameworkCore.Tools
再次执行又遇到一个新错误
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SNI_PN11, error: 26 - Error Locating Server/Instance Specified)
这里由於本机装的是SQL Server 2019 打开SQLServerManager15.msc跟services.msc
做确认後原因在於现在实体指定的是指向到本机预设MSSQLSERVER而非SQLEXPRESS
因此只要打一个.即可
修正过後的指令
Scaffold-DbContext "Server=.;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=true" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -Tables Employees,Orders
有关於SQLExpress跟MSSQLSERVER的差异可以参考这一篇来调整指令中连线字串
预设在安装SQL Server时候若没有去特别设定额外的实体名称
则默认实体名称会是., (local)或者machine name跟ip address,当然在服务中默认舍麽都没有改的情况下会显示MSSQLSERVER
有特别去指定命名SQLEXPRESS的实体则写法会是
.\SQLEXPRESS
localhost\SQLEXPRESS
当指令成功执行完後就会自动产生EF Core帮我们准备好的Model class跟Context class
DbContext当中可以看到
DbSet部分的变数名对应资料库中table名称(不可更动)
因此也会建议在table命名上建议用复数形式表示这样子才能跟Model Class加以区隔
NorthwindContext 完整程序
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
#nullable disable
namespace prjNet5_3_DbFirst.Models
{
public partial class NorthwindContext : DbContext
{
public NorthwindContext()
{
}
public NorthwindContext(DbContextOptions<NorthwindContext> options)
: base(options)
{
}
public virtual DbSet<Employee> Employees { get; set; }
public virtual DbSet<Order> Orders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
optionsBuilder.UseSqlServer("Server=.;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=true");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation("Relational:Collation", "Chinese_Taiwan_Stroke_CI_AS");
modelBuilder.Entity<Employee>(entity =>
{
entity.HasIndex(e => e.LastName, "LastName");
entity.HasIndex(e => e.PostalCode, "PostalCode");
entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");
entity.Property(e => e.Address).HasMaxLength(60);
entity.Property(e => e.BirthDate).HasColumnType("datetime");
entity.Property(e => e.City).HasMaxLength(15);
entity.Property(e => e.Country).HasMaxLength(15);
entity.Property(e => e.Extension).HasMaxLength(4);
entity.Property(e => e.FirstName)
.IsRequired()
.HasMaxLength(10);
entity.Property(e => e.HireDate).HasColumnType("datetime");
entity.Property(e => e.HomePhone).HasMaxLength(24);
entity.Property(e => e.LastName)
.IsRequired()
.HasMaxLength(20);
entity.Property(e => e.Notes).HasColumnType("ntext");
entity.Property(e => e.Photo).HasColumnType("image");
entity.Property(e => e.PhotoPath).HasMaxLength(255);
entity.Property(e => e.PostalCode).HasMaxLength(10);
entity.Property(e => e.Region).HasMaxLength(15);
entity.Property(e => e.Title).HasMaxLength(30);
entity.Property(e => e.TitleOfCourtesy).HasMaxLength(25);
entity.HasOne(d => d.ReportsToNavigation)
.WithMany(p => p.InverseReportsToNavigation)
.HasForeignKey(d => d.ReportsTo)
.HasConstraintName("FK_Employees_Employees");
});
modelBuilder.Entity<Order>(entity =>
{
entity.HasIndex(e => e.CustomerId, "CustomerID");
entity.HasIndex(e => e.CustomerId, "CustomersOrders");
entity.HasIndex(e => e.EmployeeId, "EmployeeID");
entity.HasIndex(e => e.EmployeeId, "EmployeesOrders");
entity.HasIndex(e => e.OrderDate, "OrderDate");
entity.HasIndex(e => e.ShipPostalCode, "ShipPostalCode");
entity.HasIndex(e => e.ShippedDate, "ShippedDate");
entity.HasIndex(e => e.ShipVia, "ShippersOrders");
entity.Property(e => e.OrderId).HasColumnName("OrderID");
entity.Property(e => e.CustomerId)
.HasMaxLength(5)
.HasColumnName("CustomerID")
.IsFixedLength(true);
entity.Property(e => e.EmployeeId).HasColumnName("EmployeeID");
entity.Property(e => e.Freight)
.HasColumnType("money")
.HasDefaultValueSql("((0))");
entity.Property(e => e.OrderDate).HasColumnType("datetime");
entity.Property(e => e.RequiredDate).HasColumnType("datetime");
entity.Property(e => e.ShipAddress).HasMaxLength(60);
entity.Property(e => e.ShipCity).HasMaxLength(15);
entity.Property(e => e.ShipCountry).HasMaxLength(15);
entity.Property(e => e.ShipName).HasMaxLength(40);
entity.Property(e => e.ShipPostalCode).HasMaxLength(10);
entity.Property(e => e.ShipRegion).HasMaxLength(15);
entity.Property(e => e.ShippedDate).HasColumnType("datetime");
entity.HasOne(d => d.Employee)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.EmployeeId)
.HasConstraintName("FK_Orders_Employees");
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
在继承自DbContext的NorthwindContext.cs程序中预设在
OnConfiguring方法中有一串标记为警告的代表含意是说不建议把连线资讯放在程序中
(可能不安全或者不易更换建议写於设定档)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
那可以先摆着
在此我们可看到
Employee类别对应资料库表当中型态产生的Model
Employee.cs
using System;
using System.Collections.Generic;
#nullable disable
namespace prjNet5_3_DbFirst.Models
{
public partial class Employee
{
public Employee()
{
InverseReportsToNavigation = new HashSet<Employee>();
Orders = new HashSet<Order>();
}
public int EmployeeId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Title { get; set; }
public string TitleOfCourtesy { get; set; }
public DateTime? BirthDate { get; set; }
public DateTime? HireDate { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public string HomePhone { get; set; }
public string Extension { get; set; }
public byte[] Photo { get; set; }
public string Notes { get; set; }
public int? ReportsTo { get; set; }
public string PhotoPath { get; set; }
public virtual Employee ReportsToNavigation { get; set; }
public virtual ICollection<Employee> InverseReportsToNavigation { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
}
使用精灵产生检视画面与控制器
模型类别:先选Employee
内容类别:就是选NorthwindContext
暂时勾消版面配置
预设就会把EmployeeController跟View对应操作画面检视产生出来
EmployeesController.cs的程序码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using prjNet5_3_DbFirst.Models;
namespace prjNet5_3_DbFirst.Controllers
{
public class EmployeesController : Controller
{
private readonly NorthwindContext _context;
public EmployeesController(NorthwindContext context)
{
_context = context;
}
// GET: Employees
public async Task<IActionResult> Index()
{
var northwindContext = _context.Employees.Include(e => e.ReportsToNavigation);
return View(await northwindContext.ToListAsync());
}
// GET: Employees/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employees
.Include(e => e.ReportsToNavigation)
.FirstOrDefaultAsync(m => m.EmployeeId == id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}
// GET: Employees/Create
public IActionResult Create()
{
ViewData["ReportsTo"] = new SelectList(_context.Employees, "EmployeeId", "FirstName");
return View();
}
// POST: Employees/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("EmployeeId,LastName,FirstName,Title,TitleOfCourtesy,BirthDate,HireDate,Address,City,Region,PostalCode,Country,HomePhone,Extension,Photo,Notes,ReportsTo,PhotoPath")] Employee employee)
{
if (ModelState.IsValid)
{
_context.Add(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["ReportsTo"] = new SelectList(_context.Employees, "EmployeeId", "FirstName", employee.ReportsTo);
return View(employee);
}
// GET: Employees/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employees.FindAsync(id);
if (employee == null)
{
return NotFound();
}
ViewData["ReportsTo"] = new SelectList(_context.Employees, "EmployeeId", "FirstName", employee.ReportsTo);
return View(employee);
}
// POST: Employees/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("EmployeeId,LastName,FirstName,Title,TitleOfCourtesy,BirthDate,HireDate,Address,City,Region,PostalCode,Country,HomePhone,Extension,Photo,Notes,ReportsTo,PhotoPath")] Employee employee)
{
if (id != employee.EmployeeId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(employee);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!EmployeeExists(employee.EmployeeId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["ReportsTo"] = new SelectList(_context.Employees, "EmployeeId", "FirstName", employee.ReportsTo);
return View(employee);
}
// GET: Employees/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var employee = await _context.Employees
.Include(e => e.ReportsToNavigation)
.FirstOrDefaultAsync(m => m.EmployeeId == id);
if (employee == null)
{
return NotFound();
}
return View(employee);
}
// POST: Employees/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var employee = await _context.Employees.FindAsync(id);
_context.Employees.Remove(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool EmployeeExists(int id)
{
return _context.Employees.Any(e => e.EmployeeId == id);
}
}
}
这里预设直接用精灵产生的仍然会执行报错!
主要原因就是因为warning错误标记那段我们直接忽略没调整
但事实上那段资料库连线并没有起到作用所以直接访问会报错
这里我们把NorthwindContext.cs当中的
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)这方法里面的连线字串程序码整段注解或删除掉
将连线字串("Server=.;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=true")
若你是属於有实体名称的反斜线记得要两条
("Server=.\SQLEXPRESS;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=true")
设定移置appsettings.json
预设appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
调整後的appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DbConnectonString": "Server=服务器位置;Database=资料库;Trusted_Connection=True;MultipleActiveResultSets=true;User ID=帐号;Password=密码"
}
}
所以在程序中KEY值取得就是透过DbConnectonString
在Startup.cs中加入资料库物件的DI (服务注入一律写在ConfigureServices)
加入如下程序调整
调整过後的Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using prjNet5_3_DbFirst.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace prjNet5_3_DbFirst
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<NorthwindContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("DbConnectonString")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{Controller=Home}/{Action=Index}/{id?}"
);//设置MVC默认路由
});
}
}
}
再次执行就正常了
本文同步发表至个人部落格
https://coolmandiary.blogspot.com/2021/07/net-core10ef-coredb-first.html
Ref:
教学课程:开始使用 ASP.NET MVC web 应用程序中的 EF Core
https://docs.microsoft.com/zh-tw/aspnet/core/data/ef-mvc/intro?view=aspnetcore-5.0
还原工程 (Scaffolding)
https://docs.microsoft.com/zh-tw/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli
ASP.NET Core - (DB-First) Scaffold-DbContext的错误讯息
https://dotblogs.com.tw/mis2000lab/2020/02/05/ASPnet_Core_Scaffold-DbContext_Error
对 SQL Server 资料库引擎的连线进行疑难排解
https://docs.microsoft.com/zh-tw/sql/database-engine/configure-windows/troubleshoot-connecting-to-the-sql-server-database-engine?view=sql-server-ver15
[MSSQL] 无法连线到 MS-SQL error-a-network-related-or-instance-specific-error-occurred-while-establishing
https://marcus116.blogspot.com/2017/12/error-a-network-related-or-instance-specific-error-occurred-while-establishing.html
What is the difference between SQLEXPRESS and MSSQLSERVER?
https://dba.stackexchange.com/questions/22246/what-is-the-difference-between-sqlexpress-and-mssqlserver/22248
>>: [Day 5] Ktor 微框架就如同一间毛胚屋,先来列出想要整合的框架及实作的功能清单
严格相等 型别与内容 "皆" 需相等 // 内容一样 型别不一样 false c...
Pointer to Pointer 顾名思义就是指标的指标~ 它可能是一个变数的地址的地址~ 我们...
最後一篇文,挤出了一些觉得在开发上容易踩的雷以及要注意的事情 要使用、渲染的变数除了传递进入元件的,...
前言 终於进入 Deployment 系列文的最後一篇也是非常重要的一篇了,在 K8s 系列文中的第...
零件都准备好就可以组装起来了! 前几天分别完成了redis, error, log的封装, 接下来就...