假设我有两个简单的模型(如下),其中"User"包含指向"UserDetail"(一对一关系)的导航属性:

数据库

CREATE TABLE [dbo].[UserDetail]
(
    [UserId] [int] NOT NULL PRIMARY KEY,
    [Name] varchar(100) NULL
)
CREATE TABLE [dbo].[User]
(
    [UserId] [int] NOT NULL PRIMARY KEY
)

C#.网

[Table("UserDetail"), Schema="dbo"]
public class UserDetail
{
    [Key, Required, 数据库Generated(数据库GeneratedOption.None)]
    public int UserId { get; set; }
    public string Name { get; set; }
    // Additional Properties Not Listed
}

[Table("User"), Schema="dbo"]
public class User
{
    [Key, Required]
    public int UserId { get; set; }
    // Additional Properties Not Listed

    [ForeignKey("UserId")]
    public virtual UserDetail UserDetail { get; set; }
}

现在,我们开始讨论这个问题.NET应用程序使用的是存储库体系 struct ,所以我首先要为"用户"表设置一个查询(默认实体框架行为;延迟加载):

IQueryable<User> users = DataRepository.UserRepository.List(); // 'List()' returns an IQueryable

我在这里的最终目标是简单地添加一个过滤器,该过滤器只会提取没有关联的"UserDetail"记录的"User"(即导航属性为NULL):

users = users.Where(m => m.UserDetail == null); // Also tried (m => m.UserDetail.Equals(null))
var testing = users.ToList();

但是当判断"testing"变量时,query总是返回空的(在数据库中,有"User"记录,其中包含和不包含关联的"UserDetails").根据一些初步研究,这似乎可能是由于延迟加载造成的.为了验证,我try 了以下示例:

users = users.Where(m => m.UserDetail.Name == "UserName");
var testing = users.ToList();

令我惊讶的是,这一切都如期而至;"testing"变量包含"User"记录,其中有一个关联的"UserDetail"记录,其"Name"属性等于"UserName".现在看来,延迟加载不是问题,而是IQueryable比较空导航属性(在SQL查询转换期间?)的潜在问题.

在最后一次测试中,决定try 使用Include方法,看看这是否产生了差异,但它产生的结果与第一次测试相同(即空):

users = users.Include(m => m.UserDetail).Where(m => m.UserDetail == null);
var testing = users.ToList();

所以我现在不知所措,显然没有足够的理解来产生我想要的结果.如果有人知道我在这个问题上遇到了什么问题,我希望能得到任何建议/帮助.

我的最佳猜测是IQueryable查询将导航属性转换为"JOIN"(s)而不是"LEFT JOIN"(s),因此不能用于比较空/空关联记录(这些记录根本不存在).

重述问题:

  1. 如何在中编写查询.NET/实体框架,该框架将在数据库上执行,以仅提取没有关联的"UserDetail"记录的"User"?
  2. 为什么IQueryable不能获取我在第一次测试中期望的记录?
  3. 澄清我在IQueryable功能方面所说的任何错误

提前感谢您的帮助/建议!

推荐答案

最终,问题归结为实体框架的关系配置(数据注释)不正确.试图配置一对(一或无)关系,实体框架将其解释为一对一(两者都是必需的).因此,IQueryable/Include函数正在执行连接,而不是所需的左连接.

我引用了两篇文章, bootstrap 我走上这条思路(thisthis)

所需的代码更改是C#.网络模型:

[Table("UserDetail"), Schema="dbo"]
public class UserDetail
{
    // Other articles solution was to remove the 'Required' data annotation, but I found
    // it not to be necessary (especially if it's used for validation)
    [Key, Required, DatabaseGenerated(DatabaseGeneratedOption.None)] 
    public int UserId { get; set; }
    public string Name { get; set; }
    // Additional Properties Not Listed

    // Required so that 'UserId' can be considered 'nullable';
    // not just a primary key (non-nullable)
    [ForeignKey("UserId")]
    // Needed to determine 'principle end' between 'User' and 'UserDetail' relationship
    [Required]
    public virtual UserDetail UserDetail { get; set; }
}

[Table("User"), Schema="dbo"]
public class User
{
    [Key, Required]
    public int UserId { get; set; }
    // Additional Properties Not Listed

    //[ForeignKey("UserId")] // Optional: not needed in my case but won't break anything
    public virtual UserDetail UserDetail { get; set; }
}

现在IQueryable查询按预期工作:

IQueryable<User> users = DataRepository.UserRepository.List().Where(m => m.UserDetail == null);
// Now, it only displays 'User' records that don't have an associated 'UserDetail' record
// FYI, no 'Include()' method required
var testing = users.ToList();

Csharp相关问答推荐

当前文化和当前文化之间没有区别IgnoreCase,为什么?

如果第一个匹配项为空,则规则运算不会拆分C#中分离字符串上的子菜单

减少Express Func T、bool断言中的公式中使用的条件运算符(4)数量(最多允许3个)

List T.AddRange在传递ConcurrentDictionary作为参数时引发ArgumentExcellent

在实际上是List T的 IESEARCH上多次调用First()是否不好?

程序集.加载从exe的异常

如何使用ConcurentDictionary属性上的属性将自定义System.Text.Json JsonConverter应用于该属性的值?

Unity中的刚体2D运动

如何在Parall.ForEachAsync中使用CancerationTokenSource

如何在实体框架中添加包含列表?

为具有实体框架后端的Reaction项目 Select 正确的Visual Studio模板

为什么方法的值在SELECT方法中不会更改?

在字符串C#之前获取数字

MudBlazor Textfield已禁用,但其验证工作正常

发布.NET 8 Blazor WebAssembly独立应用程序以进行静态站点部署

使用Blazor WebAssembly提高初始页面加载时间的性能

C#如何获取字符串中引号之间的文本?

忽略Visual Studio代码中的StyleCop规则

使用C#12中的主构造函数进行空判断

为什么我的UserControl没有加载到我的主窗口中?