0

我正在尝试在 Visual Studio Code 中创建 Code First Entity Framework ASP.NET Core 2 项目。我一直在关注在 Linux、macOS 和 Windows 上使用 ASP.NET Core MVC 和 Visual Studio Code 创建 Web API教程,该教程使用内存数据存储作为其DbContext. 我正在尝试将其移至 LocalDB。

使用新数据库的 ASP.NET Core 上的 EF Core 入门教程建议我应该能够通过迁移来做到这一点。

一旦有了模型,就可以使用迁移来创建数据库。

打开 PMC:

工具 -> NuGet 包管理器 -> 包管理器控制台

运行 Add-Migration InitialCreate 来构建迁移,为您的模型创建初始表集。如果您收到一条错误消息,指出“添加迁移”一词未被识别为 cmdlet 的名称,请关闭并重新打开 Visual Studio。

运行 Update-Database 以将新迁移应用到数据库。此命令在应用迁移之前创建数据库。

使用包管理器控制台的 VS 代码等效项似乎是

dotnet ef migrations add InitialCreate

添加了 EF 的 Design 命名空间...

dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet restore

并在我的 csproj 中有参考:

<ItemGroup>
    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>

但是当我之后尝试该dotnet ef migrations add命令时,它的作用就像我的 TodoItems 模型的表需要已经存在于数据库中。我的理解是迁移将根据我的模型创建表。

c:\Projects\TodoApi>dotnet ef migrations add InitialCreate -v
Using project 'c:\Projects\TodoApi\TodoApi.csproj'.
Using startup project 'c:\Projects\TodoApi\TodoApi.csproj'.
Writing 'c:\Projects\TodoApi\obj\TodoApi.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\UserName\AppData\Local\Temp\tmp945E.tmp /verbosity:quiet /nologo c:\Projects\TodoApi\TodoApi.csproj
Writing 'c:\Projects\TodoApi\obj\TodoApi.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=C:\Users\UserName\AppData\Local\Temp\tmp96FF.tmp /verbosity:quiet /nologo c:\Projects\TodoApi\TodoApi.csproj
dotnet build c:\Projects\TodoApi\TodoApi.csproj /verbosity:quiet /nologo

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:02.29
dotnet exec --depsfile c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.deps.json --additionalprobingpath C:\Users\UserName\.nuget\packages --additionalprobingpath "C:\Program Files (x86)\Microsoft SDKs\NuGetPackagesFallback" --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.runtimeconfig.json C:\Users\UserName\.nuget\packages\microsoft.entityframeworkcore.tools.dotnet\2.0.0\tools\netcoreapp2.0\ef.dll migrations add InitialCreate --assembly c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.dll --startup-assembly c:\Projects\TodoApi\bin\Debug\netcoreapp2.0\TodoApi.dll --project-dir c:\Projects\TodoApi\ --verbose --root-namespace TodoApi
Using assembly 'TodoApi'.
Using startup assembly 'TodoApi'.
Using application base 'c:\Projects\TodoApi\bin\Debug\netcoreapp2.0'.
Using working directory 'c:\Projects\TodoApi'.
Using root namespace 'TodoApi'.
Using project directory 'c:\Projects\TodoApi\'.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider...
Finding BuildWebHost method...
Using environment 'Development'.
Using application service provider from BuildWebHost method on 'Program'.
Found DbContext 'DatabaseContext'.
Finding DbContext classes in the project...
fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT CASE
          WHEN EXISTS (
              SELECT 1
              FROM [TodoItems] AS [t])
          THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
      END
System.Data.SqlClient.SqlException (0x80131904): Invalid object name 'TodoItems'.

需要做些什么来确保根据我的模型创建表?

我能想到的唯一问题是我将连接字符串内联而不是在 appsettings.json 中,但我不确定为什么这很重要,除非迁移正在寻找默认配置。

public void ConfigureServices(IServiceCollection services)
{
    // In memory: services.AddDbContext<DatabaseContext>(opt => opt.UseInMemoryDatabase("TodoList")); // <<< REMOVED
    string strCxn = "Server=(localdb)\\mssqllocaldb;Database=Contacts;Trusted_Connection=True;MultipleActiveResultSets=true"; // <<< ADDED

    services.AddDbContext<DatabaseContext>(options => options.UseSqlServer(strCxn)); // <<< ADDED
    services.AddMvc();
}

Fwiw,这些是我对 TodoApi 教程的代码所做的唯一更改,以从内存数据库移动到 LocalDB。


更新: Fwiw,我尝试更改连接字符串中的数据库名称..

string strCxn = "Server=(localdb)\\mssqllocaldb;Database=Contacts2;Trusted_Connection=True;MultipleActiveResultSets=true";

(更改ContactsContacts2,以防万一它认为,因为它最初找到了联系人数据库,所以迁移已经发生了......)

这也不起作用,尽管错误以一种表明连接字符串正在工作并被读取的方式发生了变化。

Cannot open database "Contacts2" requested by the login. The login failed.
Login failed for user 'COMPUTER-NAME\UserName'.
4

1 回答 1

0

作为DbContext的构造函数的一部分,我正在播种数据......

public class DatabaseContext : DbContext    {
    public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
    {
        this.MinimallySeedDatabase();
    }

    public void MinimallySeedDatabase()
    {
        State NY = this.States.Where(s => s.Abbr.Equals("NY")).FirstOrDefault();
        if (null == NY)
        {
            NY = new State {
                Name = "New York",
                Abbr = "NY"
            };
            this.States.Add(NY);
            this.SaveChanges();
        }

        // etc etc etc...
    }

    public DbSet<Contact> Contacts {get; set;}
    public DbSet<Address> Addresses {get; set;}
    public DbSet<AddyType> AddyTypes {get; set;}
    public DbSet<State> States {get; set;}
}

DbContext迁移执行的一部分显然是在迁移 s的表之前实例化DbSets 。由于在此示例中的构造函数需要访问 States,并且由于迁移尚未达到创建要从中提取的 States 表的程度,因此迁移失败了。

正如柯克 所说,如果我取出播种,我很好。如果你想播种,你需要将它移到构造函数以外的地方,即使构造函数中的播种在迁移尝试之外/在正常的 Kestrel 测试中工作正常。

this.MinimallySeedDatabase();对我来说,我只是在运行迁移时注释掉了。

于 2018-02-28T01:50:40.327 回答