C# 使用Linq查询将以下代码简化为一行程序

C# 使用Linq查询将以下代码简化为一行程序,c#,entity-framework,linq,lambda,C#,Entity Framework,Linq,Lambda,有两个表,用户表和费用表,具有一对多关系。因此,UserClass包含名为Expenses的ICollection类型的导航属性。我想要的是得到所有名为John的用户,并且只包括费用描述为午餐的费用。下面是我想到的。但我觉得有更好的办法。我想将其转换为: List<User> users = db.Users.Where(user => user.Name == "John").ToList(); foreach (User user in users)

有两个表,用户表和费用表,具有一对多关系。因此,UserClass包含名为Expenses的ICollection类型的导航属性。我想要的是得到所有名为John的用户,并且只包括费用描述为午餐的费用。下面是我想到的。但我觉得有更好的办法。我想将其转换为:

List<User> users = db.Users.Where(user => user.Name == "John").ToList();
            foreach (User user in users)
            {
                List<Expense> expenses = db.Expenses.Where(expense => expense.Description == "Lunch" && expense.AddedBy == user.Id).ToList();
                user.Expenses = expenses;
            }
型号:

PS:我不熟悉实体框架


谢谢。

我的建议是使用投影查询

db.Users.Where(u => u.Name == "John")
            .Where(u => u.Expenses.Any(e => e.Description == "Lunch")
            .Select(u => new
            {
                u,
                Expenses= u.Expenses.Where(e => e.Description == "Lunch")
            });
名为
u
的属性属于
User
类型,它拥有所有费用,而另一个属性
expenses
将只拥有为
启动生成的费用

或使用


我的建议是使用投影查询

db.Users.Where(u => u.Name == "John")
            .Where(u => u.Expenses.Any(e => e.Description == "Lunch")
            .Select(u => new
            {
                u,
                Expenses= u.Expenses.Where(e => e.Description == "Lunch")
            });
名为
u
的属性属于
User
类型,它拥有所有费用,而另一个属性
expenses
将只拥有为
启动生成的费用

或使用


通常,将所选数据从数据库传输到本地进程是查询中较慢的部分之一。因此,最好不要获取比实际计划使用的属性更多的属性

您需要几个
用户
,以及他们的
部分或全部费用
。每个
用户
都有一个主键
Id
,每个
费用
都有一个外键
UserId
,您可以确定它等于其
用户
Id

如果您获取1000个用户,每个用户有1000个费用,那么您的方法将传输100万
用户ID
,您已经知道其中的值。真是浪费

仅当您计划更改获取的值时才使用Include。如果没有,请使用选择`

要选择某些
用户的某些属性及其
费用

var result = myDbContext.Users               // From the collection of all Users
    .Where(user => user.Name == ...)         // Select only those that have a name ...
    .Select(user => new                      // from every remaining user make one new object
    {
        // Select only the properties you actually plan to use:
        Id = user.Id,
        Name = user.Name,
        ...

        Expenses = user.Expenses
            .Where(expense => expense.Description == ...)
            .Select(expense => new
            {
                 // again, select only the properties you plan to use
                 Id = expense.Id,   
                 Description = expense.Description,

                 // not needed, you know it equals user.Id:
                 // UserId = expense.UserId

                 ...
            })
            .ToList(),
    });
有时您确实需要
用户提供他们的费用
,例如,您需要将其用作过程的返回值。即使如此,也要使用选择和填充用例中真正需要的属性(或填充所有属性)


这样做的缺点是数据库表的布局会渗透到通信层中。如果数据库发生更改,所有调用者都需要更改,即使他们不使用新更改的属性。我的建议是在数据层之外使用您想要的类。这可能导致
userswiththeiraddress
UsersWithTheirExpenses
,甚至可能导致
UsersWithTheirFoodExpenses
。如果用户获得了一个额外的列,如
CountryCode
,则不必更改
UsersWithTheirExpenses

通常,将所选数据从数据库传输到本地进程是查询中较慢的部分之一。因此,最好不要获取比实际计划使用的属性更多的属性

您需要几个
用户
,以及他们的
部分或全部费用
。每个
用户
都有一个主键
Id
,每个
费用
都有一个外键
UserId
,您可以确定它等于其
用户
Id

如果您获取1000个用户,每个用户有1000个费用,那么您的方法将传输100万
用户ID
,您已经知道其中的值。真是浪费

仅当您计划更改获取的值时才使用Include。如果没有,请使用选择`

要选择某些
用户的某些属性及其
费用

var result = myDbContext.Users               // From the collection of all Users
    .Where(user => user.Name == ...)         // Select only those that have a name ...
    .Select(user => new                      // from every remaining user make one new object
    {
        // Select only the properties you actually plan to use:
        Id = user.Id,
        Name = user.Name,
        ...

        Expenses = user.Expenses
            .Where(expense => expense.Description == ...)
            .Select(expense => new
            {
                 // again, select only the properties you plan to use
                 Id = expense.Id,   
                 Description = expense.Description,

                 // not needed, you know it equals user.Id:
                 // UserId = expense.UserId

                 ...
            })
            .ToList(),
    });
有时您确实需要
用户提供他们的费用
,例如,您需要将其用作过程的返回值。即使如此,也要使用选择和填充用例中真正需要的属性(或填充所有属性)



这样做的缺点是数据库表的布局会渗透到通信层中。如果数据库发生更改,所有调用者都需要更改,即使他们不使用新更改的属性。我的建议是在数据层之外使用您想要的类。这可能导致
userswiththeiraddress
UsersWithTheirExpenses
,甚至可能导致
UsersWithTheirFoodExpenses
。如果用户获得了一个额外的列,比如
CountryCode
,那么
UsersWithTheirExpenses
就不需要更改。

显示您的模型类您可以尝试在条件之前使用Include方法吗我认为您不能
以这种方式包括导航属性的一些实例
.Include(user=>user.Expenses)
应该可以though@mshwf我添加了一个image@Md.AbdulAlim仍然相同如何显示您的模型类您可以尝试在where condition之前使用Include方法吗?我不认为您可以通过这种方式仅包含导航属性的某些实例
.Include(user=>user.Expenses)
应该可以though@mshwf我添加了一个image@Md.AbdulAlim仍然相同的
费用
应该是
费用
,您在末尾遗漏了一个
,并且
。其中
不返回一个
bool
,对吗?这仍然包括至少有一项费用为
Description==“午餐”
的用户的所有费用。我认为OP只需要
“John”
用户的
“午餐”
费用。(从问题中,强调我的:“获取所有名为John的用户,只包括费用描述为午餐的费用”)EF+的事情很有趣,我将为此+1。仍然
结尾处缺少;)谢谢你的评论。:)@ThierryV Entity Framework Plus的工作非常出色。谢谢。
费用
应该是
费用
,您在最后错过了一个
,并且
。其中
不返回
bool
,对吗?这仍然包括用户在中至少有一项费用的所有费用
var result = myDbContext.Users               // From the collection of all Users
    .Where(user => user.Name == ...)         // Select only those that have a name ...
    .Select(user => new                      // from every remaining user make one new object
    {
        // Select only the properties you actually plan to use:
        Id = user.Id,
        Name = user.Name,
        ...

        Expenses = user.Expenses
            .Where(expense => expense.Description == ...)
            .Select(expense => new
            {
                 // again, select only the properties you plan to use
                 Id = expense.Id,   
                 Description = expense.Description,

                 // not needed, you know it equals user.Id:
                 // UserId = expense.UserId

                 ...
            })
            .ToList(),
    });
var result = myDbContext.Users
    .Where(user => user.Name == ...)
    .Select(user => new User()
    {
        // Select only the properties you actually plan to use:
        Id = user.Id,
        Name = user.Name,
        ...

        Expenses = user.Expenses
            .Where(expense => expense.Description == ...)
            .Select(expense => new Expense()
            {
                 // again, select only the properties you plan to use
                 Id = expense.Id,   
                 Description = expense.Description,
                 ...
            })
            .ToList(),
    });