【问题标题】:Primary Key not defined, even though it already is未定义主键,即使它已经定义
【发布时间】:2022-01-21 21:26:25
【问题描述】:

我一直在开发一个 C# ASP.NET Core 应用程序,我目前正在使用 SQL Server 对象资源管理器来开发数据库。我想显示某些硬编码数据作为测试,但是当我尝试运行该页面时,出现此错误

System.InvalidOperationException: '实体类型'recent_health_issue' 需要定义一个主键。如果您打算使用无密钥实体类型,请在“OnModelCreating”中调用“HasNoKey”

我的主键已经定义了,显示页面正常工作,没有那行错误代码,所以这里我不确定。

我的数据库:

模型类:

public class recent_health_issue
{
    [Required, MinLength(3, ErrorMessage = "Enter at least 3 characters"),
     MaxLength(5)]
    public string recent_id { get; set; }

    [Required, MaxLength(25)]
    public string recent_name { get; set; }

    [Required, EmailAddress]
    public string recent_email { get; set; }

    [Required]
    public string recent_description { get; set; }
}

我的DbContext

public class RecentHealthIssueDBContext : DbContext
{
    private readonly IConfiguration _config;

    public RecentHealthIssueDBContext(IConfiguration configuration)
    {
        _config = configuration;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connectionString = _config.GetConnectionString("MyConn");
        optionsBuilder.UseSqlServer(connectionString);
    }

    public DbSet<recent_health_issue> HealthIssues { get; set; }
}

我的控制器(发生错误的地方):

public class RecentHealthController
{
    private RecentHealthIssueDBContext _context;

    public RecentHealthController(RecentHealthIssueDBContext context)
    {
        _context = context;
    }

    public List<recent_health_issue> getAllRecentHealthIssues()
    {
        List<recent_health_issue> AllRecentHealth = new List<recent_health_issue>();

        // error occured here
        AllRecentHealth = _context.HealthIssues.ToList(); 

        return AllRecentHealth;
    }

    public recent_health_issue getRecentHealthIssueById(String id)
    {
        recent_health_issue RecentHealthIssue = new recent_health_issue();
        return RecentHealthIssue;
    }
}

【问题讨论】:

  • 请也发布recent_health_issue 课程。
  • 您是否为那个定义了主键?
  • @GáborAngyal 已编辑,请检查。
  • @HansKesting 在recent_health_issue 类中吗?
  • @user15930341 是的,我的意思是那个类。您的编辑显示 recent_id[Required] 但不是 [Key] - 所以添加

标签: c# asp.net-core


【解决方案1】:

为了澄清,根据您的问题,您正在进行数据库优先开发。

这意味着您的模型和您的数据库需要完全匹配,因此如果有任何差异,那么在大多数情况下将无法正常工作。

Entity Framework 期望属性的 Pascal Case,如果它发现单个出现的属性命名或包含“Id”,那么它将假定这是关键。

如果您不遵循帕斯卡大小写(这是 C# 标准),或者不使用包含字母“Id”的属性,则必须使用 [Key] 数据注释。

当您首先创建数据库时,您为 SQL 表选择了蛇形大小写,这意味着您需要在不破坏编码约定并允许 EF 执行此操作的情况下将名称与 C# 对齐。

此外,查看您的代码和您正在做什么,因为您使用蛇形大小写来定义数据库中的名称,那么您应该对表/列名称使用数据注释,而不是更改您的属性名称以对齐, 在这里定义:https://docs.microsoft.com/en-us/ef/ef6/modeling/code-first/data-annotations#table-and-column

供您参考,EF 期望在 C# 中使用 Pascal 大小写,因此它可以实现自动化(这就是您应该使用它的原因)

public long Id {get;set;} //ef will recognise this as a Key

public long HelloCheekyThisIsMyId {get;set;} //ef will recognise this as a Key

[Key] //ef will be told this is a key
public long product_identity { get; set; }

所以你的模型应该是这样的:

[Table("recent_health_issue")]
public class RecentHealthIssue
    {
        [Key] //this shouldn't be needed but it's good for readability
        [Required, MinLength(3, ErrorMessage = "Enter at least 3 characters"), MaxLength(5)]
        [Column("recent_id")]
        public string RecentId { get; set; }

        [Required, MaxLength(25)]
        [Column("recent_name")]
        public string RecentName { get; set; }

        [Required, EmailAddress]
        [Column("recent_email")]
        public string RecentEmail { get; set; }

        [Required]
        [Column("recent_description")]
        public string RecentDescription { get; set; }
}

如文档中所定义:“不要将 Column 的 TypeName 属性与 DataType DataAnnotation 混淆。DataType 是用于 UI 的注释,被 Code First 忽略。”

你的上下文是这样的:

public class RecentHealthIssueDBContext : DbContext
{
    private readonly IConfiguration _config;
    public RecentHealthIssueDBContext(IConfiguration configuration)
    {
        _config = configuration;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string connectionString = _config.GetConnectionString("MyConn");
        optionsBuilder.UseSqlServer(connectionString);
    }

    public DbSet<RecentHealthIssue> HealthIssues { get; set; }
}

你的控制器应该是这样的:

public class RecentHealthController
{
    private RecentHealthIssueDBContext _context;

    public RecentHealthController(RecentHealthIssueDBContext context)
    {
        _context = context;
    }

    //This should be PascalCase (GetAllRecentHealthIssues)
    public List<recent_health_issue> getAllRecentHealthIssues()
    {
        List<RecentHealthIssue> allRecentHealth = new List<RecentHealthIssue>();
        allRecentHealth = _context.HealthIssues.ToList(); //error occured here
        return allRecentHealth;
    }

    //This should be PascalCase (GetRecentHealthIssuesById)
    public recent_health_issue getRecentHealthIssueById(String id)
    {
        //return recent health issues using an Id
    }
}

另外我会推荐一些防御性编程,它会在未来让你头疼。 (空检查、try/catch 块等)

这是 C# 编码约定: https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/coding-style/coding-conventions

您可以在此处找到有关可用注释的更多信息: https://docs.microsoft.com/en-us/ef/ef6/modeling/code-first/data-annotations#key

【讨论】:

    【解决方案2】:

    错误信息说你需要为表定义一个主键:

    [Key]
    [Required, MinLength(3, ErrorMessage = "Enter at least 3 characters"),
     MaxLength(5)]
    public string recent_id { get; set; }
    

    还可以尝试重命名DbContext 中的DbSet 属性以匹配数据库表名,即RecentHealthIssues 而不是HealthIssues

    public DbSet<recent_health_issue> RecentHealthIssues { get; set; }
    

    【讨论】:

    • 不起作用,出现此错误:“Microsoft.Data.SqlClient.SqlException: 'Invalid object name 'HealthIssues'.'” HealthIssues 在 DbContext 中
    • 答案已更新。请尝试重命名DbSet 属性。
    • @user15930341 表示“无效的对象名称 'HealthIssues”。完全是一个不同的问题。只是必须自己看看那里出了什么问题,对吗?只看数据库表名...
    • @MartinStaufcik 您也可以使用TableAttributeToTable 方法来更改名称。但我认为你的解决方案更干净,因为我喜欢匹配表名和属性名。
    猜你喜欢
    • 1970-01-01
    • 2021-03-11
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 1970-01-01
    相关资源
    最近更新 更多