在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.DateCreated >= options.PaymentFromDate)
                .Where(x => x.DateCreated < endDate)
                .Select(x => new 
                {
                    Method = x.Method,
                    Amount = x.Amount,
                    VatAmount = x.VatAmount
                });

由于我使用select many,我无法获得companyId。请建议一种方法,将公司id连同结果一起返回。

预订表包含CompanyId。交易不包含公司Id

public class Reservation{
  public int CompanyId { get; set; }
  public virtual ICollection<Transaction> Transactions { get; set; }
}
public class Transaction{
  public string Method{ get; set; }
  public decimal Amount{ get; set; }
  public decimal VatAmount{ get; set; }
 
}

我必须从Reservation表开始查询,因为我要从中获取相应的事务。我不能改变模型。我们是否可以通过查询同时获得交易细节和CompanyID ?

您没有发布GetAll()ReservationTransaction类的代码,因此只能猜测。

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

.Select(x => new 
{
    CompanyID = x.Transaction.CompanyId,
    Method = x.Method,
    Amount = x.Amount,
    VatAmount = x.VatAmount
});

在这种情况下,您甚至不应该从Reservation开始查询。最好查询Transactions,例如:

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
                     });

缺失预约属性

添加它。数据模型旨在促进查询,显然您需要这种关系。

关系模型不指定任何类型的图或层次结构,这是它相对于其他数据模型的主要优点。由于需要事务,因此应该查询事务。在SQL中,您只需要添加JOINWHERE IN子句来根据Transaction和CompanyID进行过滤。

存储库反模式

这暴露了下一个更严重的问题。看起来你在使用"通用"库模式——一个低层次的存储库接口,强加于像EF Core这样的高级ORM之上。这样做的问题是众所周知的,检查eg不需要存储库,实体框架核心或存储库的工作单元是2009年的新单例。

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

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

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

Reservations使用贫血存储库使得更改查询更加困难,而没有提供任何好处。查询的详细信息仍然向调用者公开。

不做透明的类,最好使用查询语法,一切都是可用的。

var result = 
  from r in reservationRepository
  where companyIds.Contains(r.CompanyId)
  from t in t.Transactions
  where t.DateCreated >= options.PaymentFromDate
    && t.DateCreated < endDate
  select new 
  {
      CompanyId = r.CompanyId,
      Method = t.Method,
      Amount = t.Amount,
      VatAmount = t.VatAmount
  };

最新更新