问题描述
我遇到了一个非常奇怪的情况,我曾希望使用C#和Linq到Entity的一段代码抛出一个异常,但是在Visual Studio中却没有,但是在Linqpad中却发生了,我想知道是否有人能够解释为什么。以下是经过测试的代码段和情况。
Db.CommunicationTemplates.Select(i => new CommunicationTemplateModel
{
ModificationUserId = (int)i.ModificationUserId,ModificationFirstName = i.ModificationUser.FirstName,ModificationLastName = i.ModificationUser.LastName
})
我的一位同事提交了此更改以进行测试。我的开发人员在不应将数据库列错误地设置为可为空的情况下
public int? ModificationUserId { get; set; }
这种情况下的测试数据非常简单,我们有3条记录。 2具有空的ModificationUserId,其中一个具有值,例如
为空 123456 空
这是具有名字和姓氏的用户表的外键。
我曾期望该代码块引发强制转换异常,但它只是滤除了违规行为,仅成功返回了包含“ 123456”的一行。为了测试代码,我将查询弹出到Linqpad中并运行它,这样做的确得到了预期的错误:
The null value cannot be assigned to a member with type system.int32 which is a non-nullable value type
这就是为什么,为什么要在Linqpad中而不是在Visual Studio中抛出该错误?
Db.CommunicationTemplates.Select(i => (int)i.ModificationUserId)
令我惊讶的是,它确实在Linqpad和Visual Studio中都引发了类型转换错误错误。之后,我回过头来尝试了以下代码:
CommunicationTemplates.Select(i => new
{
ModificationFirstName = i.ModificationUser.FirstName,ModificationLastName = i.ModificationUser.LastName
})
再次令我惊讶的是,它返回的结果不一致。在Visual Studio中,这仅成功返回了“ 123456”记录,而在LinqPad中,它仅返回了所有3条记录。我总是希望Select语句在过滤结果之前会引发错误,因为select语句确实不应该过滤内容。
所以我的问题是:
- 为什么只返回ModificationUserId时Visual Studio会引发类型错误,而在添加更多属性时却抑制该错误?可能是因为name属性已经将其过滤掉了吗?
- 为什么访问链接表上的name属性在Visual Studio中返回1结果,而在Linqpad中返回3?
- 在原始的组合示例中,Linqpad是否抛出类型错误,但是Visual Studio过滤建议应用程序之间的执行顺序不同?
我完全意识到可以改进此代码,并且已经做了改进,我只是在寻找一个解释,以说明上面的示例为何执行得与预期的不同。
解决方法
要在LINQPad和Visual Studio中获得相同的行为,必须使用相同的API。
在LINQPad中单击“添加连接”时,您可以选择以下API:LINQ-to-SQL或实体框架(LINQPad 6中的EF Core)。如果您选择LINQ-to-SQL,则如果您想要相同的行为,则还必须在Visual Studio中使用LINQ-to-SQL。而且,如果您选择EF或EF Core,请确保选择的版本与Visual Studio中使用的版本匹配。