博客 (88)

前言:

本文适合 6.x 环境,8.x 请结合参考:如何升级 ASP.NET 项目 MySql.Data 和 Connector/NET 至 8.0.x

使用 ASP.NET Core 的同学请移步:ASP.NET Core 使用 DBFirst 模式连接 MySQL 数据库


安装


开发环境


软件安装:


版本选择:

  • MySQL for Visual Studio 最新版

  • Connector/NET 版本必须与 MySql.Data 和 MySql.Data.Entity 版本相同,否则会出现 MySql.Data.MySqlClient.MySqlConnection 无法强制转换的错误


生产环境


软件安装:

  • MySQL Server - 数据库

  • Connector/NET - ADO.NET 托管提供程序


版本选择:

  • MySQL Server 最新版

  • Connector/NET 应与项目中使用的 MySql.Data 和 MySql.Data.Entity 版本一致。(某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本,某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本,为确保不出问题,严格要求版本全部一致)


升级

  • MySQL for Visual Studio:直接更新至最新版

  • MySQL Server:直接更新至最新版

  • MySql.Data 和 MySql.Data.Entity:升级至两者共有的新版本,更改 Web.config 中 MySql.Data 的版本号,并更新开发环境和生产环境的 Connector/NET 至相同版本(详细步骤见下方说明)

  • Connector/NET:视是否有相同版本的 MySql.Data 和 MySql.Data.Entity,若有,同时升级。(详细步骤见下方说明)


关于 Connector/NET 和 MySql.Data 及 MySql.Data.Entity 版本一致的说明:

某些项目在确保 Web.config 的 MySql.Data 版本号与 MySql.Data 和 MySql.Data.Entity 版本一致的前提下,允许服务端的 Connector/NET 小版本略低于 MySql.Data 和 MySql.Data.Entity 版本

某些项目允许安装比 MySql.Data 和 MySql.Data.Entity 版本略高的 Connector/NET 版本

为确保不出问题,严格要求版本全部一致。

但服务器上同时运行多个项目,一旦出现问题涉及面就很广,为了尽量减少影响,列出下面的升级步骤:

  1. 升级开发环境 Connector/NET

  2. 升级各项目的 MySql.Data 和 MySql.Data.Entity

  3. 更改 Web.config 中关于 MySql.Data 的版本号(若未自动更新,项目中搜索原版本号即可)

  4. 测试运行各项目

  5. 同时发布各项目,同时升级服务器上的 Connector/NET(升级 Connector/NET 仅需几十秒)

  6. 部分项目需要删除并重新上传 bin 目录才能生效

  7. 尽管如此,发布成功以后还是会有各种各样的问题导致无法正常打开,须要有针对性地去解决,所以升级还是要趁夜深人静的时候进行

xoyozo 6 年前
4,888

如果 .NET Core 项目发布到服务器上报以下错误:

HTTP Error 502.5 - Process Failure

Common causes of this issue:

  • The application process failed to start

  • The application process started but then stopped

  • The application process started but failed to listen on the configured port

Troubleshooting steps:

  • Check the system event log for error messages

  • Enable logging the application process' stdout messages

  • Attach a debugger to the application process and inspect

For more information visit: https://go.microsoft.com/fwlink/?LinkID=808681

在服务器上安装最新的 .NET Core Runtime 即可(Windows Server 选择 Hosting Bundle Installer)。

xoyozo 7 年前
4,439

先保存一次

Ctrl + A 全选

Ctrl + U 取消组合对象

菜单 - 编辑 - 全选 - 文本

Ctrl + Q 转换为曲线

菜单 - 文本 - 文本统计信息

看到 0 就成功了

记得“另存为”,千万不要直接“保存”,否则无法再次编辑。

转自 百度经验 7 年前
5,136
发布选项 \ 项目类型Web 窗体网站

Web 应用程序

(Web 窗体)

Web 应用程序

(MVC)

ASP.NET Core 

Web 应用程序

在发布期间预编译

Precompile during publishing

若勾选,将 .cs 文件编译为 .dll
无论是否勾选,都将 .cs 文件编译为 .dll

允许更新预编译站点

Allow precompiled site to be updatable

若不允许,则会将 .aspx 等页面也一同编译,并以内容“这是预编译工具生成的标记文件,不应删除!”代替

未进行完整的测试和分析,总结有误请指正。

xoyozo 7 年前
5,179

502.5.png

解决方法:安装最新的 .NET Core runtime 即可:https://www.microsoft.com/net/download/core#/runtime

(Windows Server 上选择 Windows Server Hosting (x64 & x86))

xoyozo 7 年前
4,906
  1. 在 NuGet 中安装 Microsoft.AspNetCore.Session 和 Newtonsoft.Json

  2. 打开 Startup.cs,在 ConfigureServices 方法中加入(视情况配置相关属性)

    services.AddSession(options =>
    {
        // 设置了一个较短的时间,方便测试
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.CookieHttpOnly = true;
    });
  3. 在 Configure 方法中加入

    app.UseSession();
  4. 添加 Extensions 文件夹并添加类 SessionExtensions.cs

    using Microsoft.AspNetCore.Http;
    using Newtonsoft.Json;
    
    public static class SessionExtensions
    {
        public static void Set<T>(this ISession session, string key, T value)
        {
            session.SetString(key, JsonConvert.SerializeObject(value));
        }
    
        public static T Get<T>(this ISession session, string key)
        {
            var value = session.GetString(key);
            return value == null ? default(T) :
                                  JsonConvert.DeserializeObject<T>(value);
        }
    }
  5. 使用方法

    HttpContext.Session.Set("abc", 123);
    var v1 = HttpContext.Session.Get<int>("abc");
    HttpContext.Session.Remove("abc");
    var v2 = HttpContext.Session.Get<int>("abc");
    // v1 = 123, v2 = 0
xoyozo 7 年前
4,795

问题:

    Invalid use of NULL value

原因:

    将字段从可空改为不可空时,数据库中存在该字段为空的行,因此更新列属性不成功。

解决:

    将数据库中已存在行中填充该字段值,再执行迁移。


问题:

    Duplicate column name 'xxx'

原因:

    数据库中已存在该列,但迁移希望执行 AddColumn,可能是手动修改了数据库结构导致的。

解决:

    删除数据库中该列(如果数据不重要),或通过删除迁移的方法回到数据库结构与 EF 快照一致的情况。


问题:

    Cannot add or update a child row: a foreign key constraint fails (`xxx`.`xxx`, CONSTRAINT `xxx` FOREIGN KEY (`xxx`) REFERENCES `xxx` (`xxx`) ON DELETE CASCADE)

原因:

    设置外键时,发现外键属性值不在导航属性所在表中。

解决:  

    添加外键属性和添加导航属性分两次迁移。

    第一次迁移:添加外键属性(字段),MySQL 可设外键属性非空,迁移成功后更改默认值 0 为真实值(即外键对应的主表中存在的值)。

    第二次迁移:添加导航属性(外键)。


xoyozo 8 年前
2,967

官方教程:Getting started with ASP.NET Core MVC and Entity Framework Core using Visual Studio


第一课:入门


Entity Framework Core NuGet 软件包


安装数据库提供程序(以 SQL Server 为例):其它数据库提供程序

Install-Package Microsoft.EntityFrameworkCore.SqlServer

该软件包依赖 Microsoft.EntityFrameworkCore 和 Microsoft.EntityFrameworkCore.Relational


新建数据模型


教程

课程注册 - 学生数据模型图

文件夹 Models 存放实体类


默认以 ID 或 类名ID 为主键列,并且是标识(即自动递增),以下代码可以取消标识,允许自定义 ID 值

[DatabaseGenerated(DatabaseGeneratedOption.None)]


导航属性:对于数据库来说就是外键,对一定义为实体类,对多定义为 ICollection<T>


字段类型可以是枚举 enum

创建数据库上下文

教程

在 Data 文件夹中创建一个名为 SchoolContext.cs 的类,继承于 DbContext

使用依赖注入注册上下文

教程


修改 Startup.cs 的 ConfigureServices 方法

在 appsettings.json 中配置数据库连接字符串

添加代码以使用测试数据初始化数据库

教程

在 Data 文件夹中创建一个名为 DbInitializer.cs 的类

修改 Startup.cs 的 Configure 方法

新建一个控制器和视图

在 Controllers 文件夹上右键,添加

MVC 依赖项选择 Minimal Dependencies 即可

会自动安装 NuGet 包:Microsoft.EntityFrameworkCore.Design 和 Microsoft.EntityFrameworkCore.SqlServer.Design

公约

表名优先来自 DbSet 属性名,其次是类名

实体属性名将映射为列名

实体属性名 ID 或 类名ID 将默认被设为主键

如果属性被命名,它将当作外键(例如,导航属性 Student 对应的实体 Student 的主键是 ID,所以 StudentID 是外键);


公约可以被覆盖,例如,可以指定表名,设置列名,并将任何属性设置为主键或外键。

异步代码

教程


第二课:新建、读取、更新和删除操作(CRUD)

自定义详细信息页面

Include() // 加载导航属性

ThenInclude() // 加载导航属性的导航属性

AsNoTracking() // 使该实体在当前上下文生命周期中不更新

SingleOrDefaultAsync() // 异步检索单个实体

路由数据

<a asp-action="Edit" asp-route-id="@item.ID">Edit</a>
<a asp-action="Edit" asp-route-studentID="@item.ID">Edit</a>

生成为

<a href="/Students/Edit/6">Edit</a>
<a href="/Students/Edit?studentID=6">Edit</a>

改进“新建页面”

在 HttpPost 的 Create 方法中,因为 ID 是自动递增的,所以可以从 Bind 中删除

[ValidateAntiForgeryToken] 搭配 if (ModelState.IsValid),用于实现验证,防止 CSRF 攻击

改进“删除页面”

在 HttpGet 的 Delete 方法中增加参数用于传递报错内容

在 HttpPost 的 Delete 方法中删除失败则 RedirectToAction 到 Delete 页面并带上报错参数

用”初始化和附加“的方法实现删除

Student studentToDelete = new Student() { ID = id };
_context.Entry(studentToDelete).State = EntityState.Deleted;

实例化要删除的实体(仅指定主键值),并将状态设置为 Deleted,即可在 SaveChanges 时实现删除,从而避免了删除必须先读取的情况。

处理交易

当 SaveChanges 时,EF 自动确保所有更改都成功或都失败,如果首先完成一些更改,然后发生错误,那么这些更改将自动回滚。

无追踪查询

什么情况下适用 AsNoTracking 方法:

在上下文中不需要更新任何实体,并且不需要加载导航属性(若需要导航属性,可以预先 Include 或稍后单独查询)

检索大量数据时,仅一小部分将被更新(稍后单独查询)

当前检索的实体需要在稍后以不同的目的附加(_context.Entry(*).State)


第三课:排序,过滤,分布和分组

添加列排序链接到学生索引页

教程

将“搜索框”添加到“学生索引”页面

教程

将分页功能添加到“学生索引”页面

教程

PaginatedList 类的使用

创建一个显示学生统计信息的关于页面

创建视图模型:在 Models 文件夹中创建一个 SchoolViewModels 文件夹,添加一个类文件 EnrollmentDateGroup.cs

修改 HomeController 添加上下文

使用 group by 进行分组查询


第四课:迁移


用于迁移的 NuGet 软件包

要使用迁移,可以使用包管理器控制台(PMC)或命令行界面(CLI)。教程

CLI 的另一种打开方式:在项目上右键 - 在文件资源管理器中打开文件夹,在地址栏上键入 cmd 回车


删除数据库的 CLI 命令

dotnet ef database drop

创建初始迁移

dotnet ef migrations add InitialCreate


创建数据库的代码位于 Migrations 文件夹中,Up 方法用于创建,Down 方法用于回滚

这时只生成了创建数据库的代码,并没有真正的创建数据库


多次创建的迁移会按时间戳的次序展示在 Migrations 文件夹中,数据库中记录了最后一次迁移的版本

检查数据模型快照

迁移会在 Migrations/SchoolContextModelSnapshot.cs 中创建当前数据库模式的快照,因此 EF Core 不必与数据库进行交互以创建迁移。

要删除最后一次迁移,执行:

dotnet ef migrations remove

将迁移应用于数据库

dotnet ef database update

执行完成会创建数据库结构,但表中的初始数据将在第一次运行时被添加


上次应用迁移之后创建的一个或多个新迁移,将在当前应用迁移时按顺序全部执行。


第五课:创建复杂的数据模型

实体图

通过使用属性自定义数据模型

[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

DataType 用于指定比数据库固有类型更具体的数据类型,上例指定为日期,而不是日期和时间

DateType 支持:Date, Time, PhoneNumber, Currency, EmailAddress 等等

DateType 支持传达数据的语义到 HTML5

DisplayFormat 用于指定格式

ApplyFormatInEditMode 指定是否当值显示在文本框中进行编辑时也应用此格式


[StringLength(50)]
[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
[RegularExpression(@"^[A-Z]+[a-zA-Z''-'\s]*$")]

StringLength 设置数据库中最大长度,并为客户端和服务端提供验证

StringLength 可以指定最小长度,但该值对数据库没有影响

StringLength 不会阻止用户输入空格,可以使用 RegularExpression 来限制

缩短最大长度会导致迁移时发出警告,为了保证顺利迁移,请先更改数据或重新选择合适的最大长度


[Column("FirstName")]
public string FirstMidName { get; set; }

上例将属性 FirstMidName 映射到数据库列名 FirstName

如何更改数据库中表的列名


[Required]

必需属性,不能为空的类型将自动处理必填字段,无需重复指定。


[Display(Name = "Last Name")]

显示属性,指定用于显示的名称


计算属性,只有一个 get 访问器,不会在数据库中生成列,例如:

public string FullName
{        
    get
    {
        return LastName + ", " + FirstMidName;
    }
}


可以将多个属性放在一行中:

[DataType(DataType.Date),Display(Name = "Hire Date"),DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]


在一对一的关系中,副表的主键名称不以副表实体 classnameID 命名,而以主表实体 classnameID 命名时,用 Key 属性来指定主键:

[Key]

或者需要以除 classnameID 或 ID 外的其它属性为主键,那么可以用 Key 


[Range(0, 5)]

指定数值范围


当有相关实体的导航属性时,EF 不要求在数据模型中添加外键属性。详情见教程


[DatabaseGenerated(DatabaseGeneratedOption.None)]

主键值由用户提供,而不是由数据库生成。


[Column(TypeName = "money")]
public decimal Budget { get; set; }

通常不需要列映射,此例将 decimal 类型的属性 Budget 映射为 money 类型的字段 Budget。


部门可能有负责人也可能没有,负责人必定是教师。因此 InstructorID 属性为教师实体的外键,并且可空,导航属性是被命名为 Administrator 的 Instructor 实体。

public int? InstructorID { get; set; }
public Instructor Administrator { get; set; }


通常,EF 允许对不可空的外键进行级联删除以久多对多关系。

例如,如果将 Department.InstructorID 属性定义为不可空,则 EF 将配置级联删除规则,以在删除部门时删除教师。如果我们想保留教师,但业务逻辑要求该 InstructorID 属性确实不可为空,则必须使用以下语句来禁用关系中的级联删除

modelBuilder.Entity<Department>()
   .HasOne(d => d.Administrator)
   .WithMany()
   .OnDelete(DeleteBehavior.Restrict)

补充,现在设计业务逻辑时会尽量避免删除操作,而使用禁用来代替,以在数据库中永久保留记录。


[DisplayFormat(NullDisplayText = "No grade")]

NullDisplayText 指定当值为 null 时的显示内容

联合主键

在多对多关系(教师到课程)的连接表(CourseAssignment)中,两个外键都不可为空,并且一同唯一标识表的每一行,因此不需要单独的主键,将 InstructorID 和 CourseID 作为一个联合主键。

定义联合主键不能通过使用属性来完成,唯一方法是使用 Fluent API,修改 Data/SchoolContext.cs 的 OnModelCreating 方法:

modelBuilder.Entity<CourseAssignment>().ToTable("CourseAssignment");
modelBuilder.Entity<CourseAssignment>()
    .HasKey(c => new { c.CourseID, c.InstructorID });

Fluent API 替代属性

protected override void OnModelCreating(ModelBuilder modelBuilder){
    modelBuilder.Entity<Blog>()
        .Property(b => b.Url)
        .IsRequired();
}

在本教程中,您只使用 Fluent API 进行数据库映射,而不能使用属性。您还可以使用 Fluent API 来指定可以使用属性执行的大多数格式化、验证和映射规则。一些属性(如 MinimumLength)不能应用 Fluent API,因为它不会更改数据库模式,它只适用于客户端和服务端验证。

一些开发人员喜欢专门使用 Fluent API,以保持实体类“干净”。当然可以混合使用属性和 Fluent API,但推荐只选择一种方式。如果混合使用,那么 Fluent API 会覆盖属性。

添加迁移

dotnet ef migrations add ComplexDataModel

如果在此时尝试运行命令 database update(不要这样做),您将收到以下错误:

ALTER TABLE语句与FOREIGN KEY约束“FK_dbo.Course_dbo.Department_DepartmentID”冲突。冲突发生在数据库“ContosoUniversity”,表“dbo.Department”,“DepartmentID”列。

这是因为在课程 Course 表增加了一个 DepartmentID 外键,而且是不可空的,又由于课程表中已经存在数据,所以无法 AddColumn。

我们可以创建一个临时部门,然后将它的 DepartmentID 值赋给 Course.DepartmentID 作为默认值。

打开 _ComplexDataModel.cs 文件,注释将 DepartmentID 添加到课程表的代码行,注释之,并在创建 Department 表的代码之后添加创建默认部门和添加 DepartmentID 的代码,详见教程


第六课:读取相关数据

预先加载、显式加载和延时加载

教程

  • 预先加载:当实体被读取时,相关数据随之被检索。即在单个连接查询中读取所有所需数据。通过 Include 和 ThenInclude 方法实现。

  • 显式加载:当实体首次读取时,不检索相关数据。如果需要再检索相关数据。显式加载会导致多次数据库查询。

  • 延时加载:当实体首次读取时,不检索相关数据。在首次尝试访问导航属性时,将自动检索该导航属性所需的数据。

* 从定义上看“显示加载”和“延时加载”比较类似,详细区别会在学完本课后有具体的了解。

创建一个显示部门名称的课程页面

教程

在课程列表中,每个课程都显示部门名称,因此使用预先加载。

在控制器中使用 Include 和 AsNoTracking

在视图中使用 @Html.DisplayFor(modelItem => item.Department.Name)

创建一个显示课程和报名的教师页面

教程

为教师页面创建一个视图模型 InstructorIndexData.cs

在控制器中多次使用 Include 和 ThenInclude 来预先加载相关数据

第一个 Include 加载办公室(一对零或一)

第二个 Include 加载课程(多对多)和报名课程的学生(多对多)

第三个 Include 加载课程(多对多)和课程所在部门(多对一)

本例中“课程的学生”和“课程的部门”是各自级联 ThenInclude 加载的,不能合并到同一个 Include 的课程中,因为 ThenInclude 不能读取多个分支的导航属性,每个分支都必须使用 Include 从教师实体调用。

在视图中给选择的教师添加 class 样式类

显式加载

教程

去掉 Include 和 AsNoTracking,然后在需要的时候附加相关的实体(上下文.Entry())来实现显式加载,以减少首次读取实体时的数据量。

await 上下文.Entry(单个实体).Collection(x=>x.导航属性).LoadAsync(); // 一对多

await 上下文.Entry(单个实体).Reference(x=>x.导航属性).LoadAsync(); // 一对一


第七课:更新相关数据

课程必须与部门关联,在新建和编辑课程时提供部门的下拉列表。

ViewBag.DepartmentID = new SelectList(departmentsQuery.AsNoTracking(), "DepartmentID", "Name", selectedDepartment);
<select asp-for="DepartmentID" class="form-control" asp-items="ViewBag.DepartmentID">
    <option value="">-- Select Department --</option>
</select>

SelectList 为下拉列表创建一个集合,允许指定默认选中项,并传递到 ViewBag。


将 .AsNoTracking() 添加到详细信息和删除方法


“一对零或一”关系:(本例是教师和办公室分配,抑或是文章和正文、学生和档案)

删除教师的办公室分配时,如果原先具有值,则删除办公室分配;

输入教师的办公室分配时,如果原先为空,则创建一个办公室分配;

更改教师的办公室分配时,更改现在有办公室分配值。

如何处理:

在 HttpGet 的 Edit 方法中,Include 办公室实体,并 AsNoTracking

在 HttpPost 的 Edit 方法中,移除除 id 以外的参数(为了不与 HttpGet 的 Edit 冲突,改名为 EditPost,并 ActionName("Edit"))

if (await TryUpdateModelAsync<Instructor>(
     instructorToUpdate,
     "",
     i => i.FirstMidName, i => i.LastName, i => i.HireDate, i => i.OfficeAssignment))

使用模型绑定器的值更新检索到的教师实体。TryUpdateModel 支持更新实体的导航属性。

我们可以直接设置实体的导航属性为 null,以便相关的行将被删除。


第八课:处理并发冲突

悲观并发,即锁定,性能差。

乐观并发:

[Timestamp]
public byte[] RowVersion { get; set; }

添加一个 timestamp 类型的 RowVersion 字段

详见教程


第九课:继承

教程


第十课:进阶专题

调用“返回实体”的查询

为了防止 SQL 注入,使用参数化查询:

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }
    
    string query = "SELECT * FROM Department WHERE DepartmentID = {0}";
    
    var department = await _context.Departments
        .FromSql(query, id)
        .Include(d => d.Administrator)
        .AsNoTracking()
        .SingleOrDefaultAsync();
        
    if (department == null)
    {
        return NotFound();
    }
        
    
    return View(department);
}

调用“返回其他类型”的查询

编写 SQL,而非 LINQ:

public async Task<ActionResult> About()
{
    List<EnrollmentDateGroup> groups = new List<EnrollmentDateGroup>();
    var conn = _context.Database.GetDbConnection();
    try
    {
        await conn.OpenAsync();
        using (var command = conn.CreateCommand())
        {
            string query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
                + "FROM Person "
                + "WHERE Discriminator = 'Student' "
                + "GROUP BY EnrollmentDate";
            command.CommandText = query;
            DbDataReader reader = await command.ExecuteReaderAsync();

            if (reader.HasRows)
            {
                while (await reader.ReadAsync())
                {
                    var row = new EnrollmentDateGroup { EnrollmentDate = reader.GetDateTime(0), StudentCount = reader.GetInt32(1) };
                    groups.Add(row);
                }
            }
            reader.Dispose();
        }
    }
    finally
    {
        conn.Close();
    }
    return View(groups);
}

调用“更新”查询(批量更新)

使用参数化查询批量更新数据,返回受影响行数:

ViewData["RowsAffected"] = 
    await _context.Database.ExecuteSqlCommandAsync(
        "UPDATE Course SET Credits = Credits * {0}",
        parameters: multiplier);

检查发送到数据库的 SQL

有时,可以看到发送到数据库的实际 SQL 查询很有帮助。

第一步:设置一个断点

第二步:调试模式运行程序

第三步:在“输出”窗口可以看到 SQL 查询语句

自动变化检测

EF 通过将实体的当前值与原始值进行比较来确定实体如何更改。

一些方法会导致自动更改检测:

DbContext.SaveChages

DbContext.Entry

ChangeTracker.Entries

如果您正在跟踪大量实体,并且您在循环中多次调用上述方法之一,则可以通过临时关闭 AutoDetectChangesEnabled 属性,能显著提升性能。

_context.ChangeTracker.AutoDetectChangesEnabled = false;

从现有数据库反向工程

完整教程

常见错误

问:ContosoUniversity.dll 由另一个进程使用

答:在 IIS Express 中停止站点。

问:迁移在 Up 和 Down 方法中没有代码

原因:在运行migrations add命令时有未保存的更改

答:运行migrations remove命令,保存代码更改并重新运行migrations add命令。




xoyozo 8 年前
5,285

如果我们直接更改模型的属性名,在迁移的时候会报错:

Data\DbInitializer.cs(,): error CS0117: '表' does not contain a definition for '新列名'


原因是它无法判断是把什么列名更改为什么列名(比如一次改多列呢),那么我们需要用 [Column("列名")] 来映射


方法一:

先加上 [Column("新列名")] ,执行迁移

再修改模型的属性名并删除 [Column("新列名")],执行迁移


方法二:

先加上 [Column("原列名")] ,同时修改模型的属性名,执行迁移,

再删除 [Column("原列名")],执行迁移


xoyozo 8 年前
4,610