C# 内联使用对象初始化器与将变量1传递给EF Select之间的细微差别

C# 内联使用对象初始化器与将变量1传递给EF Select之间的细微差别,c#,entity-framework,C#,Entity Framework,将Func保存为变量,然后将其传递给实体框架select,与在select中内联键入转换有什么区别 Func<Models.Contact,ViewModels.Contact> ToViewModel = c => new ViewModels.Contact() { ID = c.ID, ... UserName = c.User.UserName }; ... return dc.Contact

将Func保存为变量,然后将其传递给实体框架select,与在select中内联键入转换有什么区别

Func<Models.Contact,ViewModels.Contact> ToViewModel = 
    c => new ViewModels.Contact()
    {
        ID = c.ID,
        ...
        UserName = c.User.UserName
    };

...

return dc.Contacts.Select(ToViewModel);
我这样问是因为尽管这两种方法都有效,但它们对null和其他一些东西的反应却有细微的不同,我不明白为什么

例如,在这种情况下,联系人可能有用户,也可能没有用户,因此用户可能为空,也可能不为空。在内联输入初始化器时,它将使属性正常地失败为null。但是,当通过变量传递相同的初始值设定项时,它将抛出NullReferenceException

为什么会这样


请注意,我希望保存初始化器的原因是,它可以在每个CRUD操作中重用,以便从WebApi返回对象。必须在类周围复制和粘贴select,这会很烦人,特别是当需要在响应中添加或删除属性时。

您的第二个示例编译为一个表达式,EF在服务器上运行。(使用
IQueryable
界面)
它变成了一个使用外部联接的SQL查询,外部联接不会生成空引用异常

您的第一个示例不是表达式树,因此它通过
IEnumerable
接口并在客户机上执行。

通过将
ToViewModel
更改为
Expression
可以使其行为与第一个示例相同。第二个示例编译为
Expression
,EF在服务器上运行。(使用
IQueryable
界面)
它变成了一个使用外部联接的SQL查询,外部联接不会生成空引用异常

您的第一个示例不是表达式树,因此它通过
IEnumerable
接口并在客户机上执行。
通过将
ToViewModel
更改为
表达式,可以使其行为与第一个示例相同

return dc.Contacts.Select(c => new ViewModels.Contact()
{
    ID = c.ID,
    ...
    UserName = c.User.UserName
});