代码之家  ›  专栏  ›  技术社区  ›  Nigel B

.NET核心实体框架InvalidOperationException

  •  4
  • Nigel B  · 技术社区  · 7 年前

    我有一个简单的模型

    [Table("InterfaceType")]
    public class InterfaceType
    {
        [Key]
        public int InterfaceTypeId { get; set; }
        public string Description { get; set; }
    }
    

    public DbSet<InterfaceType> InterfaceTypes { get; set; }
    

    在我的控制器里

    List<InterfaceType> types = _context.InterfaceTypes.FromSql(
                "SELECT * FROM [Interfaces].[Control].[InterfaceType]").ToList();
    

    InvalidOperationException:“FromSql”操作的结果中不存在所需的列“InterfaceID”。

    List<InterfaceType> types = _context.InterfaceTypes.FromSql(
                "SELECT InterfaceTypeId, Description FROM [Interfaces].[Control].[InterfaceType]").ToList();
    

    我也尝试过:

    interfacesOverview.SelectedInterface.InterfaceTypes = _context.InterfaceTypes.ToList();
    

    通过fluent api声明后:

     protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
           modelBuilder.Entity<InterfaceType>().ToTable("InterfaceType", "Control");
        }
    

    同样的结果。

    为清楚起见,以下是MSSQL中的表格:

        CREATE TABLE [Control].[InterfaceType](
        [InterfaceTypeId] [tinyint] NOT NULL,
        [Description] [varchar](25) NULL,
     CONSTRAINT [PK_InterfaceType] PRIMARY KEY CLUSTERED 
    (
        [InterfaceTypeId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    

    使现代化

    我已经查看了EF生成的SQL:

        SELECT [i].[InterfaceTypeId], [i].[Description], [i].[InterfaceID] FROM [Control].[InterfaceType] AS [i]
    

    它是从哪里来的?

    7 回复  |  直到 7 年前
        1
  •  5
  •   Ivan Stoev    7 年前

    它是从哪里来的?

    首先,应该清楚的是,它不是来自所显示的“简单”(但显然不完整)模型。

    Discriminator 列,因此它不能来自继承。还有一种可能性是,您明确定义了一个名为 InterfaceID 没有注意到它很小。

    接口ID 匹配FK属性的一个EF核心常规名称/我的列名是关系引入的常规FK的明确指示。例如,第二个模型如下:

    public class Interface
    {
        public int ID { get; set; }
        // or
        // public int InterfaceID { get; set; }
        public ICollection<InterfaceType> InterfaceTypes { get; set; }
    }
    

    正如在报告中所解释的那样 Relationships - Single Navigation Property EF核心文档主题:

    只包含一个导航属性(没有反向导航,也没有外键属性)就足以拥有由约定定义的关系。

    附带的示例显示 Blog / Post public List<Post> Posts { get; set; } 财产 突出显示。

    所有EF核心运行时行为都基于模型元数据。无论数据库的结构是什么,更重要的是EF Core认为它是基于模型类、数据注释和流畅配置的,以及它是否与数据库模式匹配。更简单的检查方法是生成迁移并检查它是否与数据库模式匹配。

        2
  •  2
  •   WueF    7 年前

    我对这个问题的理解是,EF创建了一个 Shadow Property 在模型类中,可能通过在 Interface

    我还觉得EFCore使用的ModelSnapshot和数据库中表的真实状态(可能是挂起的迁移)不匹配。仔细检查,你的情况如何 InterfaceType <YourDbContext>ModelSnapshot.cs ,并检查是否有您丢失的财产。

        3
  •  2
  •   Steve Py    7 年前

    我的猜测是,您还拥有一个注册在上下文中的“接口”表,该表包含对InterfaceType的引用。接口将声明一个InterfaceTypeId字段,但是对于EF,如果您使用的是带有ForeignKey的HasOne,请检查您是否意外地指定了如下内容:

    .HasOne(x => x.InterfaceType).WithOne().HasForeignKey<InterfaceType>("InterfaceId");

    对于具有InterfaceType的接口,其映射更像:

    .HasOne(x => x.InterfaceType).WithMany();

    这可能潜入了您的其他关联实体之一。通常这些都是打字错误,自动完成选择了错误的类型,你没有注意到。如果该映射存在于任何类上,EF将期望在InterfaceType上找到InterfaceId列。搜索 HasForeignKey<InterfaceType> 看看有没有什么不寻常的事。

        4
  •  1
  •   Steve    7 年前

    List<InterfaceType> types = _context.InterfaceTypes.ToList();

    其次,您是否对模型应用了任何更改,并忘记将其持久化到数据库中,因为可能是列在类中是正确的,但在数据库中不是正确的。这是我在使用代码模型时经常忘记做的事情。

    以下是有关FromSQL的一些附加信息:- https://docs.microsoft.com/en-us/ef/core/querying/raw-sql

    https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/

        5
  •  0
  •   daniell89    7 年前

    数据库生成属性

    [Table("InterfaceType")]
    public class InterfaceType
    {
       [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity),Key()]
       public int InterfaceTypeId { get; set; }
       ...
    
        6
  •  0
  •   dj079    7 年前

    为了检查是否有一种方法可以复制,我创建了一个样本 .NET Core Console application 为了检查这一点,在我的例子中,我能够毫无例外地从数据库中检索数据。

    我知道你有其他的模型也有同样的代码, 如果您将有问题的代码移到原始解决方案之外,您可能会 能够找出你是否有明显的遗漏。

    我试图尽可能地遵循您的代码,试图重现这个问题,其中一些内容我必须更改。

    .NET Core 和 EF Core 您使用的版本。在我的样本中,我使用了:

    1. Microsoft.EntityFrameworkCore 2.2
    2. Microsoft.EntityFrameworkCore.Design 2.2
    3. Microsoft.EntityFrameworkCore.SqlServer 2.2

    我创建了:

    1. 根据您的样品制作模型课
    2. 根据示例使用OnModelCreating创建上下文类

    执行以下命令 dotnet core

    1. dotnet restore
    2. dotnet build
    3. dotnet ef migrations add InitMgr
    4. dotnet ef database update
    5. 在表中添加了一些测试记录

    复制了记录检索代码,从查询中删除了“[Interfaces]”,并调试了下面的代码。

            var _context = new InterfaceTypeContext ();
            List<InterfaceType> types = _context.InterfaceTypes.FromSql ("SELECT * FROM [Control].[InterfaceType]").ToList ();
    

    我能够从数据库中检索数据。

    enter image description here

    Minimal, Complete, and Verifiable example 这

        7
  •  0
  •   JohnyL    7 年前

    以下几点对我很有用:

    插入一些数据:

    insert into [Control].[InterfaceType] values (1, 'Desc1'), (2, 'Desc2');
    

    class SOContext : DbContext
    {
        public DbSet<InterfaceType> InterfaceTypes { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var conn_string = @"Server=(localdb)\mssqllocaldb;Database=Interfaces;Trusted_Connection=Yes;";
            optionsBuilder.UseSqlServer(conn_string);
        }
    }
    
    [Table("InterfaceType", Schema = "Control")]
    public class InterfaceType
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None), Key]
        public byte InterfaceTypeId { get; set; }
        public string Description { get; set; }
        public override string ToString() =>
            $"Id: {InterfaceTypeId} | Description: {Description}";
    }
    
    // Output:
    // Id: 1 | Description: Desc1
    // Id: 2 | Description: Desc2