C# 在Linq中使用“选择”和“同时选择多个”

C# 在Linq中使用“选择”和“同时选择多个”,c#,entity-framework,linq,C#,Entity Framework,Linq,我正在尝试在以下查询中获取公司id List<int> companyIds=new List<int> {4, 5, 6, 7}; var result = reservationRepository.Where(r => companyIds.Contains(r.CompanyId)) .SelectMany(t => t.Transactions) .Where(x => x

我正在尝试在以下查询中获取公司id

List<int> companyIds=new List<int> {4, 5, 6, 7};
   var result = reservationRepository.Where(r => companyIds.Contains(r.CompanyId))
                .SelectMany(t =>  t.Transactions)
                .Where(x => x.DateCreated >= options.PaymentFromDate)
                .Where(x => x.DateCreated < endDate)
                .Select(x => new 
                {
                    Method = x.Method,
                    Amount = x.Amount,
                    VatAmount = x.VatAmount
                });

我必须用Reservation表开始查询,因为我要从中获取相应的事务我无法更改模型。有什么方法可以通过查询同时获得交易详细信息和公司ID吗?

您没有发布
GetAll()
保留
交易
类的代码,因此只能猜测

SelectMany
仅返回
Transaction
对象。接下来的调用只查看
事务
对象,而不查看
预订
。如果
Transaction
具有
Reservation
属性,则可以使用
x.Reservation.CompanyId
返回该值,例如:

.Select(x => new 
{
    CompanyID = x.Transaction.CompanyId,
    Method = x.Method,
    Amount = x.Amount,
    VatAmount = x.VatAmount
});
在这种情况下,您甚至不应该从
预订开始查询。最好查询
交易
,例如:

var transactions = db.Transactions
                     .Where(x=>companyIds.Contains(x.Reservation.CompanyId) &&
                               x.DateCreated >= options.PaymentFromDate &&
                                x.DateCreated < endDate)
                     .Select(x => new 
                     {
                         CompanyId = x.Reservation.Id
                         Method = x.Method,
                         Amount = x.Amount,
                         VatAmount = x.VatAmount
                     });
var transactions=db.transactions
.Where(x=>CompanyId.Contains(x.Reservation.CompanyId)&&
x、 DateCreated>=options.PaymentFromDate&&
x、 创建日期<结束日期)
.选择(x=>new
{
CompanyId=x.Reservation.Id
方法=x.方法,
金额=x.金额,
VatAmount=x.VatAmount
});
缺少预订属性

加上它。数据模型是为了方便查询,您显然需要这种关系

关系模型没有指定任何类型的图或层次结构,这是它相对于其他数据模型的主要优势。因为您需要事务,所以应该查询事务。在SQL中,只需添加一个
JOIN
WHERE In
子句,即可按事务和公司ID进行筛选

存储库反模式

这暴露了下一个更严重的问题。看起来您使用的是“通用”存储库模式—一种低级别存储库接口,强加于更高级别的ORM(如EF Core)之上。这方面的问题是众所周知的,检查例如或从2009年

数据库集已经是一个存储库。DbContext已经实现了工作单元和断开连接的操作,并结合了多个实体存储库

贫血的存储库不需要隐藏数据访问细节,这就是ORM的用途。有意义的是一个专门的、多实体的存储库,为特定的用例服务,隐藏合并实体、验证检查、添加实现公共查询的方法的细节,用于所有涉及的实体

例如,这个专门的存储库可以有一个
GetTransactionsByCompany(int)
方法,它可以封装整个查询并真正隐藏细节


预订使用贫乏的存储库
会使更改查询变得更加困难,而不会带来任何好处。查询的详细信息仍然向调用方公开。

您没有发布
GetAll()
保留
事务
类的代码,因此只能猜测

SelectMany
仅返回
Transaction
对象。接下来的调用只查看
事务
对象,而不查看
预订
。如果
Transaction
具有
Reservation
属性,则可以使用
x.Reservation.CompanyId
返回该值,例如:

.Select(x => new 
{
    CompanyID = x.Transaction.CompanyId,
    Method = x.Method,
    Amount = x.Amount,
    VatAmount = x.VatAmount
});
在这种情况下,您甚至不应该从
预订开始查询。最好查询
交易
,例如:

var transactions = db.Transactions
                     .Where(x=>companyIds.Contains(x.Reservation.CompanyId) &&
                               x.DateCreated >= options.PaymentFromDate &&
                                x.DateCreated < endDate)
                     .Select(x => new 
                     {
                         CompanyId = x.Reservation.Id
                         Method = x.Method,
                         Amount = x.Amount,
                         VatAmount = x.VatAmount
                     });
var transactions=db.transactions
.Where(x=>CompanyId.Contains(x.Reservation.CompanyId)&&
x、 DateCreated>=options.PaymentFromDate&&
x、 创建日期<结束日期)
.选择(x=>new
{
CompanyId=x.Reservation.Id
方法=x.方法,
金额=x.金额,
VatAmount=x.VatAmount
});
缺少预订属性

加上它。数据模型是为了方便查询,您显然需要这种关系

关系模型没有指定任何类型的图或层次结构,这是它相对于其他数据模型的主要优势。因为您需要事务,所以应该查询事务。在SQL中,只需添加一个
JOIN
WHERE In
子句,即可按事务和公司ID进行筛选

存储库反模式

这暴露了下一个更严重的问题。看起来您使用的是“通用”存储库模式—一种低级别存储库接口,强加于更高级别的ORM(如EF Core)之上。这方面的问题是众所周知的,检查例如或从2009年

数据库集已经是一个存储库。DbContext已经实现了工作单元和断开连接的操作,并结合了多个实体存储库

贫血的存储库不需要隐藏数据访问细节,这就是ORM的用途。有意义的是一个专门的、多实体的存储库,为特定的用例服务,隐藏合并实体、验证检查、添加实现公共查询的方法的细节,用于所有涉及的实体

例如,这个专门的存储库可以有一个
GetTransactionsByCompany(int)
方法,它可以封装整个查询并真正隐藏细节

预订使用贫乏的存储库
会使更改查询变得更加困难,而不会带来任何好处。查询的详细信息仍向呼叫者公开。