我正在使用实体Framework和LINQ来执行这两个表之间的连接:
var query =
orders.Join(
orderdetails,
order => order.Code,
orderdt => orderdt.Order.Code,
(order, orderdt)
=> new
{
Code = order.Code,
WarehouseDivision = orderdt.WarehouseDivision,
Type = order.Type,
SupplierCode = order.SupplierCode,
SupplierDescription = order.SupplierDescription,
ExpectedDeliveryDate = orderdt.ExpectedDeliveryDate
});
联接工作正常。现在,对于每个联接行,我需要选择具有最小ExpectedDelivery Date的行。关于如何实现这一目标的任何提示?
我在您的加入中看到了一些奇怪的东西。
每个订单都有一个代码。每个OrderDetail都有一个订单,也有一个代码。
如果Order与OrderDetails之间存在一对多关系,则每个Order都具有零个或多个OrderDetails。每个OrderDetail都完全属于一个Order,即外键指向的Order。那是与OrderDetail.Order相同的Order吗?
在这种情况下,对于此代码的每个OrderDetail,Order.Code等于OrderDetail.Order.Code。对这些值执行联接不是很有用。
我认为您的意思是同时使用主键和外键。
无论采用哪种方式,无论您是在键上还是在属性代码上进行联接,解决问题的方法都是执行GroupJoin而不是Join。
如果您遵循了entity framework code first conventions,您将获得类似以下内容:
class Order
{
public int Id {get; set;} // Primary key
... // other Order properties
// every Order has zero or more OrderDetails (one-to-many)
public virtual ICollection<OrderDetail> OrderDetails {get; set;}
}
class OrderDetail
{
public int Id {get; set;}
public DateTime ExpectedDeliveryDate {get; set;}
... // other OrderDetail properties
// every OrderDetail belongs to exactly one Order, using foreign key
public int OrderId {get; set;}
public virtual Order Order {get; set;}
}
可能是您对属性使用了不同的标识符,但主要是虚拟属性。
在实体框架中,非虚拟属性表示表中的列,虚拟属性表示表之间的关系(一对多,多对多)。
从每个订单中,给我一些属性,以及具有最小ExpectedDeliveryDate的OrderDetail的一些属性。
GroupJoin在主/外键上:
var OrdersWithOldestOrderDetail = dbContext.Orders // GroupJoin Orders
.GroupJoin(dbContext.OrderDetails, // with OrderDetails
order => order.Id, // from every Order take the Id
orderDetail => orderDetail.OrderId, // from every OrderDetail take the OrderId
(order, orderDetailsOfThisOrder) => new // take the Order with all its matchin OrderDetails
{ // to make one new
// Select the Order properties that you plan to use:
...
// Select the OrderDetail with the minimum ExpectedDeliveryDate
// To do this, order by ascending deliveryDate
// then Select the properties you want to used
// and take the FirstOrDefault
EarliestDeliveredOrderDetail = orderDetailsOfThisOrder
.OrderBy(orderDetail => orderDetail.ExpectedDeliveryDate)
.Select(orderDetail => new
{
...
})
.ToList(),
});
如果您真的想加入您所说的属性:
var result = dbContext.Orders // GroupJoin Orders
.GroupJoin(dbContext.OrderDetails, // with OrderDetails
order => order.Code, // from every Order take the Code
orderDetail => orderDetail.Order.Code, // from every OrderDetail take Order.Code
(order, orderDetailsWithThisCode) => new // take the Order with all its matchin OrderDetails
{
... etc, same as above
[如果您使用的是实体框架,则实际上需要选择“所有带有OrderDetails的订单”,“所有带有学生的学校”,“带有组件的所有产品”:所有项目以及所有相关子项目,通常,使用ICollections而不是自己执行连接会更简单:
var OrdersWithOrderDetails = dbContext.Orders.Select(order => new
{
// Select the Order properties that you plan to use:
...
EarliestDeliveredOrderDetail = order.OrderDetails
.OrderBy(orderDetail => orderDetail.ExpectedDeliveryDate)
.Select(orderDetail => new
{
// Select the OrderDetail properties that you plan to use:
...
})
.FirstOrDefault(),
})
看看如果您使用ICollection而不是(Group-)join会感觉如何?实体框架知道您的关系,并使用正确的(外部)键为您执行正确的联接。
事实上,我很少创建自己的Join。大多数时候,我使用虚拟属性。