EF Code First将额外的列添加到模型中不存在的查询中

And*_*w4R 3 sql-generation ef-code-first

这是我关于SO的第一个问题.

我有一个ASP.NET 4.0 MVC3项目,使用EF Code First作为ORM和FluentMigrator进行版本迁移.我有Message实体类,如下所示:

public class Message
{
    [Key]
    [Column("Message_Id")]
    public int Id { get; set; }

    public DateTime CreatedTime { get; set; }

    [Required]
    [StringLength(MaxSubjectLength)]
    public string Subject { get; set; }

    [Required]
    [StringLength(MaxBodyLength)]
    public string Body { get; set; }

    public Link Link { get;set; }
}
Run Code Online (Sandbox Code Playgroud)

没有定义自定义映射,并且MSSQL Server 2012数据库表消息:

CREATE TABLE [dbo].[Messages](
    [Message_Id] [int] IDENTITY(1,1) NOT NULL,
    [CreatedTime] [datetime] NOT NULL,
    [Subject] [nvarchar](78) NOT NULL,
    [BodyHtml] [nvarchar](2000) NOT NULL,
    [Link_Id] [int] NULL,
    [Collection_Id] [int] NULL,
    [MessageType] [nvarchar](30) NOT NULL,
 CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED 
(
    [Message_Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Messages]  WITH CHECK ADD  CONSTRAINT [FK_Messages_Collection] FOREIGN KEY([Collection_Id])
REFERENCES [dbo].[Collections] ([Id])
GO

ALTER TABLE [dbo].[Messages] CHECK CONSTRAINT [FK_Messages_Collection]
GO

ALTER TABLE [dbo].[Messages]  WITH CHECK ADD  CONSTRAINT [FK_Messages_Link] FOREIGN KEY([Link_Id])
REFERENCES [dbo].[Links] ([Id])
GO

ALTER TABLE [dbo].[Messages] CHECK CONSTRAINT [FK_Messages_Link]
GO
Run Code Online (Sandbox Code Playgroud)

Link_Id,Collection_Id和MessageType列都在该表中,因为我想进行TPH继承(实际上我想做TPT继承然后切换到TPH,我猜它会解决我的问题,但事实并非如此).

现在我希望LinkMessage和CollectionMessage类看起来像这样:

public class LinkMessage : Message
{
    public int? Link_Id { get;set; }
}

public class CollectionMessage : Message
{
    public int? Collection_Id { get;set; }
}
Run Code Online (Sandbox Code Playgroud)

所以问题是:即使没有定义继承(即只存在Message实体),当我删除链接导航属性,重建我的项目,(甚至重新创建数据库等)并执行简单查询时,var a = DBContext.Messages.ToList(); EF会生成以下查询:

SELECT 
[Extent1].[Message_Id] AS [Message_Id], 
[Extent1].[CreatedTime] AS [CreatedTime], 
[Extent1].[Subject] AS [Subject], 
[Extent1].[BodyHtml] AS [BodyHtml], 
[Extent1].[Link_Id] AS [Link_Id]
FROM [dbo].[Messages] AS [Extent1]
Run Code Online (Sandbox Code Playgroud)

为什么它仍然包含Link_Id?它不再是模型了.这将导致继承问题 - 当我使用上面的子类进行TPH(或TPT)继承时,app失败并显示错误'无效列名'Link_Id1''.为什么选择Link_Id1?怎么会发生这种情况?我完全糊涂了.'Collection_Id'列表现正常.这两列是相同的.我试图重新创建数据库,杀死应用程序的所有进程(甚至重新启动我的电脑),尝试加载以前的修订版本并删除了Message.Link_Id属性,尝试使用数据而没有 - 相同的行为.我试图谷歌的东西,但最终没有任何东西,因为实际上我甚至不知道如何进行正确的搜索查询和搜索我没有给我任何东西,我花了第二天与它...

以下是它们生成的查询和SQL:

var b = DBContext.Messages.OfType<CollectionMessage>();

SELECT 
[Extent1].[Message_Id] AS [Message_Id], 
'0X0X' AS [C1], 
[Extent1].[CreatedTime] AS [CreatedTime], 
[Extent1].[Subject] AS [Subject], 
[Extent1].[BodyHtml] AS [BodyHtml], 
[Extent1].[Collection_Id] AS [Collection_Id], 
[Extent1].[Link_Id1] AS [Link_Id1]
FROM [dbo].[Messages] AS [Extent1]
WHERE [Extent1].[MessageType] = N'CollectionMessage'


var b = DBContext.Messages.OfType<LinkMessage>();

SELECT 
[Extent1].[Message_Id] AS [Message_Id], 
'0X0X' AS [C1], 
[Extent1].[CreatedTime] AS [CreatedTime], 
[Extent1].[Subject] AS [Subject], 
[Extent1].[BodyHtml] AS [BodyHtml], 
[Extent1].[Link_Id] AS [Link_Id], 
[Extent1].[Link_Id1] AS [Link_Id1]
FROM [dbo].[Messages] AS [Extent1]
WHERE [Extent1].[MessageType] = N'LinkMessage'


var b = DBContext.Messages;

SELECT 
[Extent1].[Message_Id] AS [Message_Id], 
CASE WHEN (((CASE WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit)) AND ((CASE WHEN ([Extent1].[MessageType] = N'CollectionMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit))) THEN '0X' WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN '0X0X' ELSE '0X1X' END AS [C1], 
[Extent1].[CreatedTime] AS [CreatedTime], 
[Extent1].[Subject] AS [Subject], 
[Extent1].[BodyHtml] AS [BodyHtml], 
CASE WHEN (((CASE WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit)) AND ((CASE WHEN ([Extent1].[MessageType] = N'CollectionMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit))) THEN CAST(NULL AS int) WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN [Extent1].[Link_Id] END AS [C2], 
CASE WHEN (((CASE WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit)) AND ((CASE WHEN ([Extent1].[MessageType] = N'CollectionMessage') THEN cast(1 as bit) ELSE cast(0 as bit) END) <> cast(1 as bit))) THEN CAST(NULL AS int) WHEN ([Extent1].[MessageType] = N'LinkMessage') THEN CAST(NULL AS int) ELSE [Extent1].[Collection_Id] END AS [C3], 
[Extent1].[Link_Id1] AS [Link_Id1]
FROM [dbo].[Messages] AS [Extent1]
Run Code Online (Sandbox Code Playgroud)

为什么要查询Link_Id和Link_Id1列?有人帮帮我,我错过了什么?

UPD:当我删除自定义DBInitializer并使Code First为我创建DB时,它会在'Messages'表中创建额外的列'Link_Id1'.

And*_*w4R 6

对不起,伙计们,我知道应该是一些小愚蠢的错误,但并不认为这是愚蠢的.实际上一个Link实体收集了Messages它.这个属性使用不多,所以我们没有注意到其他属性.当我删除它 - 一切都开始工作.

所以它开始是非常有趣的问题,但最终得到了非常明显的答案 - 人为因素.

对于所有刚接触EF并且正在同一个洞穴中的人,我会留下一个注释:EF除非有参考,否则不能"记住"某些属性.因此,如果您遇到类似的麻烦,请仔细检查您的代码,并请其他人这样做,没有魔力!

我现在不能upvote,所以soadyp,Gert Arnold - 谢谢你的帮助!