我有一个简单的模型
[Table("InterfaceType")]
public class InterfaceType
{
[Key]
public int InterfaceTypeId { get; set; }
public string Description { get; set; }
}
以及在我的DbContext中
public DbSet<InterfaceType> InterfaceTypes { get; set; }
以及在我的控制器中
List<InterfaceType> types = _context.InterfaceTypes.FromSql(
"SELECT * FROM [Interfaces].[Control].[InterfaceType]").ToList();
哪个返回错误:
InvalidOperationException:'FromSql'操作的结果中没有所需的列'InterfaceID'。
我正在类似的其他方法中使用FromSql,尽管这些模型确实包含InterfaceId,但没有问题。为什么该操作不在模型中时会期望InterfaceId。我也尝试了以下相同的结果。
List<InterfaceType> types = _context.InterfaceTypes.FromSql(
"SELECT InterfaceTypeId, Description FROM [Interfaces].[Control].[InterfaceType]").ToList();
我也尝试过:
interfacesOverview.SelectedInterface.InterfaceTypes = _context.InterfaceTypes.ToList();
通过流畅的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]
它从哪里获取InterfaceID?
答案 0 :(得分:5)
它从哪里获取InterfaceID?
首先,应该清楚,它不是来自所示的“简单”(但显然是不完整的)模型。
由EF生成的SQL清楚地表明您没有重命名PK属性生成的列,也没有Discriminator
列,因此它不能来自继承。而且,您明确定义了称为InterfaceID
的阴影属性而没有注意到它的机会很小。
所有这些以及名称InterfaceID
与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 Core文档主题中所述:
仅包含一个导航属性(没有反向导航,也没有外键属性)就足以具有由约定定义的关系。
及其随附的示例显示了Blog
/ Post
模型,其中public List<Post> Posts { get; set; }
中只有Blog
属性被突出显示。
所有EF Core运行时行为均基于模型元数据。数据库的结构无关紧要,更重要的是EF Core认为它基于模型类,数据注释和流畅的配置,以及是否与数据库架构匹配。一种更简单的检查方法是生成迁移并检查其是否与数据库模式匹配。
因此,如果关系是有意的,则必须更新数据库以匹配模型。否则,您需要更新模型以匹配数据库-通过删除或忽略集合导航属性(或更正导致差异的无效数据注释/流利配置)。
答案 1 :(得分:2)
我对这个问题的理解是,EF创建了一个Shadow Property
在模型类中,可能是由于在Interface
模型中部分发现的关系所致。
我还感到EFCore使用的ModelSnapshot与数据库中表的实际状态(可能是由于挂起的迁移)不匹配。仔细检查您在InterfaceType
中的<YourDbContext>ModelSnapshot.cs
的状况,并检查您是否缺少某个属性。
答案 2 :(得分:1)
首先为什么不使用
List<InterfaceType> types = _context.InterfaceTypes.ToList();
其次,您是否对模型应用了任何更改,却忘记将其保留到数据库中,因为该列可能在您的类中是正确的,但在数据库中却不正确。使用Code-FirstModel时,我常常会忘记这样做。
以下是FromSQL的一些附加信息:-https://docs.microsoft.com/en-us/ef/core/querying/raw-sql
有关迁移的更多详细信息,在这里:-https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/
我希望这会有所帮助。
答案 3 :(得分:1)
我的猜测是,您还有一个在上下文中注册的“接口”表,该表包含对InterfaceType的引用。接口将声明一个InterfaceTypeId字段,但是对于EF,如果将HasOne与ForeignKey一起使用,请检查是否没有意外分配以下内容:
.HasOne(x => x.InterfaceType).WithOne().HasForeignKey<InterfaceType>("InterfaceId");
对于具有InterfaceType的接口,它将被映射为:
.HasOne(x => x.InterfaceType).WithMany();
这可能已经潜入您的其他关联实体之一。通常,这些是拼写错误,在这种情况下,自动完成功能在没有引起您注意的情况下选择了错误的类型。如果您的任何类上都存在该映射,则EF将期望在InterfaceType上找到一个InterfaceId列。在HasForeignKey<InterfaceType>
上进行搜索,看看是否有什么异常之处。
答案 4 :(得分:0)
也许尝试添加 DatabaseGeneratedAttribute
[Table("InterfaceType")]
public class InterfaceType
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity),Key()]
public int InterfaceTypeId { get; set; }
...
答案 5 :(得分:0)
仅检查是否有可以重现的方法,创建了一个示例.NET Core Console application
进行检查,就我而言,我能够毫无例外地从数据库中检索数据。
我了解您还有其他可以使用相同代码的模型, 如果您将有问题的代码移出原始解决方案之外,则可能是 能够弄清楚您是否缺少明显的东西。
我试图尽可能地遵循您的代码,以尝试重现此问题,在此我必须进行一些更改。
我不知道您使用了哪个.NET Core
和EF Core
版本。在我的示例中,我使用了:
我创建了:
按照以下列出的顺序按以下dotnet core
命令执行:
dotnet restore
dotnet build
dotnet ef migrations add InitMgr
dotnet ef database update
复制您的记录检索代码,从查询中删除“ [Interfaces]”并调试下面的代码。
var _context = new InterfaceTypeContext ();
List<InterfaceType> types = _context.InterfaceTypes.FromSql ("SELECT * FROM [Control].[InterfaceType]").ToList ();
我能够从数据库中检索数据。
如果您共享Minimal, Complete, and Verifiable example供他人调试并帮助您找到解决方案,这也将有所帮助 这个。
答案 6 :(得分:0)
以下对我有用:
插入一些数据:
insert into [Control].[InterfaceType] values (1, 'Desc1'), (2, 'Desc2');
C#:
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