系统.InvalidOperationException:'未找到适合实体类型“HealthCheck”的构造函数。'

7

当我尝试通过EF Core向数据库添加内容时,我遇到了这个错误。

System.InvalidOperationException:'未找到适合的构造函数以用于实体类型“ HealthCheck”。以下构造函数具有无法绑定到实体类型属性的参数:不能在“ HealthCheck(string title,string hctype,string link)”中绑定“ hctype ”。'

这是我的HealthCheck类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Application.Models
{
    public class HealthCheck
    {
        public HealthCheck(string title, string hctype, string link)
        {
            Title = title;
            HCType = hctype;
            Link = link;
        }

        public int Id { get; set; }
        public string Title { get; set; }
        public string HCType { get; set; }
        public string Link { get; set; }
    }
}

我的仓储上下文

using Microsoft.EntityFrameworkCore;
using Application.Models;

namespace Application.Repository
{
    public class RepositoryContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(
                @"Server=(localdb)\mssqllocaldb;Database=healthcheck;Integrated Security=True");
        }

        //public DbSet<HealthCheck> HealthChecks { get; set; }
        //public DbSet<UserHealthCheck> UserHealthChecks { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<HealthCheck>().ToTable("HealthCheck");
            modelBuilder.Entity<UserHealthCheck>().ToTable("UserHealthCheck");
        }
    }
}

我的代码库

using Application.Models;

namespace Application.Repository
{
    public class Repository
    {
        public void InsertHealthCheck(HealthCheck healthCheck)
        {
            using (var db = new RepositoryContext())
            {
                db.Add(healthCheck);
                db.SaveChanges();
            }
        }
    }
}

这里就是“InsertHealthCheck()”被调用的地方

[Route("/api/HealthCheck/Website")]
        [HttpPost]
        public ActionResult WebsiteStatus([FromBody] WebsiteDataModel websiteData)
        {
            HealthCheck data = new HealthCheck(websiteData.Title, "Website", websiteData.Url);
            try
            {
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(websiteData.Url);
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                HttpStatusCode HealthCheckStatusCode = myHttpWebResponse.StatusCode;
                myHttpWebResponse.Close();
                return Ok(HealthCheckStatusCode);
            }
            catch(UriFormatException)
            {
                return Ok("Check url.");
            }
            catch (Exception)
            {
                return Ok("400");
            }
            finally
            {
                repository.InsertHealthCheck(data);
            }
        }


如果您能帮我一下,我将不胜感激。如果您需要我发布代码的其他部分,请提出要求。

此外,我刚刚开始学习EF Core,如果我做了什么很愚蠢的事情,请指出来。
5个回答

18
提供一个无参构造函数可以避免这个问题,但这并不是 OP 情况下错误的真正原因。EF Core 2.1 及更高版本使用严格的约定将构造函数参数映射到实体属性名称。 它希望构造函数参数的名称是 Pascal-case 中属性名称的真正驼峰表示法。如果您将参数名称从 "hctype" 更改为 "hCType",则不应该出现错误,并且如果您的领域驱动设计方法要求这样做会有问题,则不需要提供无参构造函数。
然而,如果您只是为了方便而提供参数化构造函数,但调用者能够使用 "new" 运算符实例化 HealthCheck 是没有问题的,那么简单地添加无参构造函数是可以接受的。

1
基于领域驱动设计,我们是否最好使用“private” 访问修饰符来定义无参构造函数或空构造函数? - Mohsen Saniee

9
您缺少空构造函数:
public class HealthCheck
{
   // here
   public HealthCheck()
   {
   }

   public HealthCheck(string title, string hctype, string link)
   {
       Title = title;
       HCType = hctype;
       Link = link;
   }

   public int Id { get; set; }
   public string Title { get; set; }
   public string HCType { get; set; }
   public string Link { get; set; }


}

试着这样做


1
谢谢!我确信这一定是非常简单的事情。 - Facundo Gabriel Garca Conejero

4

我遇到了这个异常。

实体类型“Blog”找不到合适的构造函数。以下构造函数有参数无法绑定到实体类型属性:无法在“Blog(string name)”中绑定“name”;无法在“Blog(int id, string name)”中绑定“name”。

我通过两种方式来缓解这个问题。

首先看一下我的 Blog 类。

public class Blog
{
    public Blog(string name)
    {
        Name = name;
    }

    private Blog(int id, string name)
    {
        Id = id;
        Name = name;
    }
    public int Id { get; private set; }
    public string Name { get; } // Note: No setter, it's a readonly prop. 
    public List<Post> Posts { get; } = new();
}

注意,Name属性没有setter方法。
因此第一种方法是添加一个私有的setter方法。现在它不再是只读属性,可以在类内部设置它。
public string Name { get; private set; }

这个应用程序正常运行,没有出现异常。

但是,如果您坚持在此处保留Name属性为只读,还有另一种方法。我们需要添加一个显式配置到上下文中,如下所示。在这里,我们告诉Ef Core显式地进行映射。Ef Core默认不会映射只读属性。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    // Ef does not map readonly properties by default, we have to 
    // ask ef to map the Name even though Name is readonly
    modelBuilder.Entity<Blog>(b => b.Property(e => e.Name));
}

1
记录一下:这甚至适用于只有 getter 的属性(EF Core 5)。 - Gert Arnold

0

获取此错误的方式有很多:-( 以下是另一种:

只读属性不遵循公约映射[即使 PropertyName / constructorParameterNames 准确地遵循 PascalCase / camelCase 匹配公约...],因此没有映射到与构造函数匹配的属性。像这样映射属性应该会使构造函数无误地使用:

modelBuilder.Entity<A>(b =>
{
    b.Property(e => e.Id).ValueGeneratedNever();
    b.Property(e => e.Name);                
});

https://github.com/dotnet/efcore/issues/14336

但是这里是截至2021年的EF Core规则摘要,应该涵盖大多数可行和不可行的情况:

https://learn.microsoft.com/en-us/ef/core/modeling/constructors


0

由于 HealthCheck 类代表数据库中的一个,因此您必须提供一个空构造函数。
尝试以下实现,并告诉我是否仍然收到相同的错误:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Application.Models
{
    public class HealthCheck
    {
        public HealthCheck()
        {
        }

        public HealthCheck(string title, string hctype, string link)
        {
            Title = title;
            HCType = hctype;
            Link = link;
        }

        public int Id { get; set; }
        public string Title { get; set; }
        public string HCType { get; set; }
        public string Link { get; set; }
    }
}

如果你检查我的答案,你会发现我在你之前就已经写了,所以你的答案和我的完全一样。 - Milenko Jevremovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接