微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使LINQ to EF和LINQ to normal collection返回相同的值?

如何解决如何使LINQ to EF和LINQ to normal collection返回相同的值?

我使用LINQ to EF。

我有一个Item实体,其中包含购买的集合。

并非所有物品都有购买。我想进行一次选择查询,当该商品没有购买时,它会为LastPurchaseQuantity(int?)和LastPurchaseDate(DateTime?)返回null。

我做了下面的LINQ SELECT查询

当我在应用程序中将其运行到EF时,它将完全返回我想要的内容。但是,当我尝试对其进行单元测试时,它会返回LastPurchaseQuantity和LastPurchaseDate的认值-最小日期和0。

如何优化查询,使其对EF和单元测试的工作方式相同?它应该返回值或null。

我想我不需要FirstOrDefault,而是FirstOrNull()方法

        var query = _itemsRepository.All()
            .Where(x => x.UserId == userId)
            .Select(x => new ItemOverviewDto()
            {
                Id = x.Id,Name = x.Name,ReplenishmentPeriod = x.ReplenishmentPeriod,NextReplenishmentDate = x.NextReplenishmentDate,LastReplenishmentDate = x.Purchases
                                 .OrderByDescending(y => y.ReplenishmentDate)
                                 .Select(m => m.ReplenishmentDate)
                                 .FirstOrDefault(),LastReplenishmentQuantity = x.Purchases
                                 .OrderByDescending(y => y.ReplenishmentDate)
                                 .Select(m => m.Quantity)
                                 .FirstOrDefault(),});

        return query.ToList();

编辑:对于我的单元测试,我通过了一个假的IQueryable集合。

var allItems = BuildItemsCollection();
ItemsRepositoryMock.Setup(x => x.All()).Returns(allItems);

解决方法

我看到的唯一选择是将类型转换添加到可为空的类型中

        LastReplenishmentDate = x.Purchases
                         .OrderByDescending(y => y.ReplenishmentDate)
                         .Select(m => (DateTime?) m.ReplenishmentDate)
                         .FirstOrDefault(),LastReplenishmentQuantity = x.Purchases
                         .OrderByDescending(y => y.ReplenishmentDate)
                         .Select(m => (int?) m.Quantity)
                         .FirstOrDefault(),
,

您的BuildItemsCollection方法设置返回的Items是否包含填充的Purchases集合? EF会将Linq表达式转换为SQL,因此其行为可能与查询对象时有所不同。

在定义具有集合导航属性的实体时,一个建议是始终初始化这些导航属性:

public class Item
{
     // Item fields...

     public virtual ICollection<Purchase> Purchases { get; set; } = new List<Purchase>();
}

这仅有助于避免在访问新项目的“购买”时出现空引用异常。但是,在您的情况下,请检查BuildItemsCollection是否正在填充Purchases:

private IQueryable<Item> BuildItemsCollection()
{
    var items = new List<Item> ( new [] 
    {
         new Item 
         {
             // ....
             Purchases = new List<Purchase> ( new []   
             { 
                 new Purchase // Expected purchase..
                 {
                     // ..
                 },new Purchase 
                 {
                     // ..
                 }
             }
        },new Item 
        {
             // ...
             Purchases = new List<Purchase> ( new []   
             { 
                 new Purchase // Expected purchase..
                 {
                     // ..
                 },}
        }
    }
    return items.AsQueryable();
}

更新:

在使用数据库排序规则和按字符串进行的任何过滤方式处理内存集与数据库时的另一个注意事项。根据您的数据库排序规则设置,数据库可能以不区分大小写的模式运行(SQL Server的默认设置),因此查询如下:

.Where(x => x.Name = "george")

当对带有“ George”作为名称且具有CI排序规则的表运行时,这将返回一条记录。当针对内存IQueryable的填充对象运行时,不会。 (值得考虑是否/何时测试数据过滤器)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。