我已经设置了以下Program.cs:
using Api.Models;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddDbContext<MarketDb>(options =>
{
var connectionString = builder.Configuration.GetConnectionString("MySqlLocal");
var serverVersion = new MySqlServerVersion(new Version(8, 3, 0));
options.UseMySql(connectionString, serverVersion).EnableSensitiveDataLogging().EnableDetailedErrors();
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// build app
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.MapGet("/hello", () => "Hello World!");
app.MapGet("/regions", async (MarketDb dbContext) =>
{
return await dbContext.RegionId.ToListAsync();
}).WithName("GetRegions").WithOpenApi();
app.Run();
连接字符串在appsettings.Development.json中定义:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"MySqlLocal": "server=127.0.0.1;port=3306;database=dbservice_test;user=root;password=password"
}
}
此外,数据库上下文在 MarketDb.cs 中定义:
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
public class MarketDb : DbContext
{
public MarketDb(DbContextOptions<MarketDb> options) : base(options) { }
public DbSet<CompletedDates> CompletedDates { get; set; }
public DbSet<RegionId> RegionId { get; set; }
public DbSet<TypeId> TypeId { get; set; }
public DbSet<MarketData> MarketData { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MarketData>()
.HasOne(m => m.Date)
.WithMany(d => d.MarketData)
.HasForeignKey(m => m.DateID);
modelBuilder.Entity<MarketData>()
.HasOne(m => m.Region)
.WithMany(r => r.MarketData)
.HasForeignKey(m => m.RegionID);
modelBuilder.Entity<MarketData>()
.HasOne(m => m.Type)
.WithMany(t => t.MarketData)
.HasForeignKey(m => m.TypeID);
}
}
}
当我尝试到达
/hello
端点时,我收到“Hello World!”正如预期的那样。
当我尝试到达
/regions
端点时,我收到以下错误:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
据我所知,我已严格遵循该错误消息的建议,但它仍然绝对无法连接到我在 Docker 容器中运行的 MySql 实例。我可以通过adminer容器访问数据库,也可以使用mysql浏览器访问数据库。我不明白这里有什么问题?
以下是我的模型文件,以防有用:
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
[Table("type_id")]
public class TypeId : DbContext
{
public int Id { get; set; }
public string Value { get; set; }
public ICollection<MarketData> MarketData { get; set; } = new List<MarketData>();
public TypeId(int id, string value)
{
Id = id;
Value = value ?? throw new ArgumentNullException(nameof(value));
}
}
}
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
[Table("region_id")]
public class RegionId : DbContext
{
public int Id { get; set; }
public string Value { get; set; }
public ICollection<MarketData> MarketData { get; set; } = new List<MarketData>();
public RegionId(int id, string value)
{
Id = id;
Value = value ?? throw new ArgumentNullException(nameof(value));
}
}
}
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
[Table("market_data")]
[PrimaryKey(nameof(DateID), nameof(RegionID), nameof(TypeID))]
public class MarketData : DbContext
{
public int DateID { get; set; }
public CompletedDates Date { get; set; }
public int RegionID { get; set; }
public RegionId Region { get; set; }
public int TypeID { get; set; }
public TypeId Type { get; set; }
public double Average { get; set; }
public double Highest { get; set; }
public double Lowest { get; set; }
public long Volume { get; set; }
public long OrderCount { get; set; }
public MarketData(int dateID, CompletedDates completedDate, int regionID, RegionId region, int typeID, TypeId type, double average, double highest, double lowest, long volume, long orderCount)
{
DateID = dateID;
Date = completedDate ?? throw new ArgumentNullException(nameof(completedDate));
RegionID = regionID;
Region = region ?? throw new ArgumentNullException(nameof(region));
TypeID = typeID;
Type = type ?? throw new ArgumentNullException(nameof(type));
Average = average;
Highest = highest;
Lowest = lowest;
Volume = volume;
OrderCount = orderCount;
}
}
}
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
namespace Api.Models
{
[Table("completed_dates")]
public class CompletedDates : DbContext
{
public int Id { get; set; }
public DateOnly Date { get; set; }
public ICollection<MarketData> MarketData { get; set; } = new List<MarketData>();
}
}
问题是双重的:
首先:我不应该从
DbContext
继承我的数据模型类:
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
[Table("type_id")]
---public class TypeId : DbContext
+++public class TypeId
{
public int Id { get; set; }
public string Value { get; set; }
public ICollection<MarketData> MarketData { get; set; } = new List<MarketData>();
public TypeId(int id, string value)
{
Id = id;
Value = value ?? throw new ArgumentNullException(nameof(value));
}
}
}
...etc.
这暴露了一个警告,我试图消除该警告,即我的 MarketData 模型中的导航属性(TypeId、RegionId 和 CompletedDates)无法提供给构造函数。
相反,它们将成为必需属性,这在实体框架中强制底层 MySql 数据库中的非空关系。这也消除了对显式构造函数的需要:
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Api.Models
{
[Table("market_data")]
[PrimaryKey(nameof(DateID), nameof(RegionID), nameof(TypeID))]
public class MarketData
{
public int DateID { get; set; }
public required CompletedDates Date { get; set; }
public int RegionID { get; set; }
public required RegionId Region { get; set; }
public int TypeID { get; set; }
public required TypeId Type { get; set; }
public double Average { get; set; }
public double Highest { get; set; }
public double Lowest { get; set; }
public long Volume { get; set; }
public long OrderCount { get; set; }
}
}
所以,总而言之,这只是一个愚蠢的错误,我一遍又一遍地读着。