4

这是我关于 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; }
}

没有定义自定义映射,以及 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

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; }
}

所以问题是:即使没有定义继承(即只存在消息实体),当我删除链接导航属性、重建我的项目(甚至重新创建数据库等)并执行简单查询时,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]

为什么它仍然包含 Link_Id?它不再是模型。这将导致继承问题 - 当我使用上面的子类进行 TPH(或 TPT)继承时,应用程序失败并出现错误“无效的列名 '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]

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

UPD:当我删除自定义 DBInitializer 并使用 Code First 为我创建数据库时,它会在“消息”表中创建额外的列“Link_Id1”。

4

3 回答 3

8

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

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

对于所有不熟悉 EF 并且掉进同一个洞穴的人,我会留下一条说明:除非引用了某些属性,否则 EF 无法“记住”某些属性。因此,如果您确实遇到类似的麻烦,请仔细检查您的代码并请其他人来做,没有魔法!

我现在不能投票,所以soadypGert Arnold - 感谢您的帮助!

于 2013-04-23T10:18:26.943 回答
4

从这里开始http://msdn.microsoft.com/en-us/data/jj591583.aspx 任何机会

public Link Link { get;set; }

正在拖入 Link_Id

于 2013-04-22T14:58:50.117 回答
2

如果您的模型中只有Messageand (必须Link),那么总会有一列Link_Id可以容纳Message.Link

如果您Message的模型中还关闭了派生类Link_Id,则始终为属性生成LinkMessage.Link_Id。您不能Link在派生类中拥有基类和外键值。现在 EF 只注意到有一个属性LinkMessage.Link_Id,除此之外还有一个导航属性Link。对于后者,Link_Id不再可用,因此 EF 创建了Link_Id1.

您必须将两者LinkLink_Id放在同一个类中,以使 EF 将它们视为一个外键(外键关联)的两个部分。它可能看起来像这样:

public class LinkMessage : Message
{
    [ForeignKey("Link")]
    public int? Link_Id { get; set; }
    public Link Link { get; set; }
}
于 2013-04-22T19:21:29.300 回答