有没有办法找出哪个表列导致与实体框架的转换出错?

Posted

技术标签:

【中文标题】有没有办法找出哪个表列导致与实体框架的转换出错?【英文标题】:Is there a way to find out which table column is causing an error in conversion with Entity Framework? 【发布时间】:2021-10-13 07:22:56 【问题描述】:

我有一个简单的 MVC 应用程序,它使用我的 API 通过实体框架 DbContext 在 SQL Server DB 中注册信息。

我可以将应用程序中的实体注册到数据库中。但是,每当我尝试从数据库中检索它以在我的应用程序中显示它时,我都会收到一个 System.InvalidCastException 向我抛出的消息,并且它携带的消息并不是非常有用,它只是说“指定的转换无效”。 .尝试执行context.MyTable.ToList()时抛出异常。

我已经查看了我的模型,但我没有看到任何类型不匹配,并且我使用 fluentAPI 来处理 boolbit 之间的转换,所以我怀疑是那个字段(我有一个不同的应用程序,其中问题没有发生,我使用该方法来处理布尔值)

这是我的表的代码:

Create table Property(
    Id int IDENTITY (1,1) PRIMARY KEY,
    Description varchar(60) not null,
    SalesPrice decimal(18,2) not null,
    Building bit not null,
    ZoningClass varchar(1) not null,
    Profit decimal(18,2),
    ImgPath varchar(300)
)

型号:

public class Property
    
        [Key]
        [DisplayName("Prop ID")]
        [Column("Id", TypeName="int")]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id  get; set; 

        [DisplayName("Property Description")]
        [Required(ErrorMessage = "Description cannot be empty.")]
        [Column("Description", TypeName="varchar(60)")]
        [StringLength(60, ErrorMessage = "Description cannot be over 60 characters.")]
        public string Description  get; set; 

        [Required(ErrorMessage = "Sales price cannot be empty")]
        [Range(0, double.MaxValue, ErrorMessage ="Sales price cannot be negative.")]
        [DisplayName("Sales Price ($)")]
        [Column("SalesPrice", TypeName ="decimal(18,2)")]
        public decimal SalesPrice  get; set; 

        [Required]
        [DisplayName("Property has building.")]
        [Column("Building")]
        public bool Building  get; set; 

        [Required(ErrorMessage = "Specify a Zoning class")]
        [DisplayName("Zoning Class")]
        [Column("ZoningClass", TypeName ="varchar(1)")]
        
        public string ZoningClass  get; set; 

        [Column("Profit", TypeName = "decimal(18,2)")]
        public decimal Profit  get; set; 

        [Required(ErrorMessage = "Indicate Image Route")]
        [StringLength(300, ErrorMessage = "Route cannot be over 300 characters")]
        [Column("ImgPath", TypeName = "varchar(300)")]
        
        public string ImgPath  get; set; 
    

处理注册到数据库的控制器方法:

    [HttpPost]
    public ActionResult Register(Property model)
    
        model.Profit = 0;
        if (ModelState.IsValid)
        
            switch (model.ZoningClass)
            
                case "A":
                    model.Profit = model.SalesPrice * (decimal)0.05;
                    break;
                case "B":
                    model.Profit = model.SalesPrice * (decimal)0.04;
                    break;
                case "C":
                    model.Profit = model.SalesPrice * (decimal)0.03;
                    break;
                default:
                    model.Profit = 0;
                    break;
            
            //requestHandler simply sends an HTTP request to the API.
            var res = requestHandler.AddProperty(model);
            if(res.StatusCode == HttpStatusCode.Created)
            
                TempData["Created"] = "Client Created";
            
            return View("CreateProperty", new Property());
        
        return View("CreateProperty", model);
    

以及 DbContext 本身

    public class PropertyContext : DbContext

    public DbSet<Property> Property  get; set; 

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    
        optionsBuilder.UseSqlServer(@"Server=myserver;Database=mydb; User Id=myuser; Password=mypass;");
    

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<Property>().
            Property(p => p.Building).
            HasConversion(
                v => v ? 1 : 0,
                v => (v == 1)
            );
    

因此,模型中的字段与表中的列之间似乎存在正确的对应关系。我看不出是哪一个导致了错误,并且调试应用程序对我没有帮助,因为异常本身对我来说不是很易读。

【问题讨论】:

SqlClient 中有一个突出的错误,它将无法转换某些decimal 值。见github.com/dotnet/SqlClient/issues/95 我在您发布的实际代码中的任何地方都看不到context.MyTable.ToList()。能贴出实际抛出异常的方法吗? 我没有包含它,因为它实际上就是这样做的,它使用 using 语句和上下文打开连接,然后只执行 context.Property.ToList(); 那么为什么要进行转换?布尔值自动映射到位字段,即 0 或 1。 我不知道这种隐式转换,对于以前的应用程序我也有类似的问题。在以前的应用程序中,问题最终是由其他原因引起的,但我仍然将转换留在那里以防万一。无论如何,那段代码是处理值转换的有效流利的 api 代码,所以它真的不应该是一个问题。 【参考方案1】:

尝试删除已转换。没见过有人用过

   modelBuilder.Entity<Property>().
            Property(p => p.Building).
            HasConversion(
                v => v ? 1 : 0,
                v => (v == 1)
            );

如果你需要一些特别的东西,最好把代码放在 get;设置;

您的相关要求也太多了。例如 [Required(ErrorMessage = "销售价格不能为空")]。它永远不会为空,因为它不可为空,因此永远不会被触发。 您只能使用 [Range(0, double.MaxValue, ErrorMessage ="销售价格不能为空,应为正数。")]。或列名称,因为它们与属性名称相同。

根据 sql 脚本,Profit 列可能为空,恕我直言,属性也应该可以为空

public decimal? Profit  get; set; 

【讨论】:

bitbool 转换内置于 SqlClient:docs.microsoft.com/en-us/dotnet/framework/data/adonet/… 是的,你是对的。我认为在这里使用它没有任何意义。特别是如果它引起问题 正如我在帖子中指出的那样:这不是转换,因为我有另一个应用程序使用该确切的代码位,并且对于在此应用程序中引发异常的相同操作执行良好。 试试吧。如果您不需要,最好现在将其删除,以后不要使用。 删除后什么也没做。我知道这段代码可能无关紧要,但它也不是导致问题的原因,这是使用 fluent api 处理转换的有效语法。我现在的猜测是,由于控制器中发生了十进制乘法,问题正在发生。它最有可能改变数字的精度。【参考方案2】:

在您的数据库中,Profit 可以为空,因为您没有设置 not null,因此您的属性必须可以为空。改成

public decimal? Profit  get; set; 

【讨论】:

以上是关于有没有办法找出哪个表列导致与实体框架的转换出错?的主要内容,如果未能解决你的问题,请参考以下文章

实体框架,如何将 IQueryable 与多个 where 转换为 SQL 一起使用?

有没有办法避免在我的 UI 项目中添加对实体框架的引用而不使用 Web 服务作为中间人?

找出在 UIActivityViewController 中单击了哪个图标

将 mogenerator 与 Core Data 实体一起使用会导致保存数据存储时出错

当node升级后导致webpack打包出错,node-saas出问题的解决办法

有没有办法找出哪个文件使用了require_once?