其中NavigationProperty.date> = Date,即使数据库具有有效数据,也返回空列表

问题描述 投票:1回答:2

我有以下对象:

public class DeviceTests
{
    public int Id { get; set; }

    public int? EnvironmentId { get; set; }
    public virtual Common.Environment Environment { get; set; } 
//.. other prop's
}

public class Environment
{
    public int Id { get; set; }
    public string Version { get; set; }
    public string User { get; set; }
    public string Computer { get; set; }
    public string OSVer { get; set; }
    public DateTime TimeStamp { get; set; }
}

我试图得到一个IQueryable回来,当处理时,将产生一组DeviceTests对象,其中他们的Environment对象在给定范围内有一个时间戳。两个对象(表)之间存在一对一的关系。

到目前为止,尝试了以下成功:

var allTests = context.DeviceTests.Where(x =>
                x.Environment.TimeStamp >= searchTime && 
                x.Environment.TimeStamp <= endTime).ToList();

返回:[]。 (如果提供的日期应该是8)

var evs = context.Environment.Where(x =>
                    x.TimeStamp >= searchTime && 
                    x.TimeStamp <= endTime).Select(x=> x.Id).ToList();
var allTests = context.DeviceTests.Where(x =>
                evs.Containes(x.EnvironmentId)).ToList();

evs返回8个正确的环境ID。所有测试都返回空列表。

var allTests = context.DeviceTests.Include(x=> x.Environment).Where(x =>
                x.Environment.TimeStamp >= searchTime && 
                x.Environment.TimeStamp <= endTime).ToList();

返回:[]。 (如果提供的日期应该是8)

我甚至试过这个,看看我是否可以退回DeviceTest

var evs = context.Environment.Where(x =>
          x.TimeStamp >= searchTime && 
          x.TimeStamp <= endTime).Select(x=> x.Id).ToList();
int temp = evs[0];    
var allTests = context.DeviceTests.Where(x =>
          x.EnvironmentId == temp).ToList();

但是在evs中仍然有8个正确的环境id,allTests返回空列表。

首先使用EF代码设置数据库。代码由API控制器使用的服务执行。

加成

我现在正在考虑从错误的角度解决这个问题。如果不想直接编写SQL,你会如何解决这个问题?如果在代码第一个db中有上述对象,则需要根据存储在环境对象中的时间戳获取DeviceTests的集合。对任何建议开放。

更新

我做了一个小型的迷你项目来复制我的问题。问题是我的迷你项目没有复制我的问题并正常工作。因此我认为这不是linq查询的问题我认为问题现在已经存在于其他地方了。任何要看的区域的指针将不胜感激。

c# entity-framework linq
2个回答
0
投票

没有你的数据就无法真正测试它,但看起来它可能会起作用:

var allTests =
    from deviceTest in context.DeviceTests
    where deviceTest.EnvironmentId.HasValue
    let environment = deviceTest.Environment
    where environment.TimeStamp <= endTime &&
          environment.TimeStamp >= searchTime
    select deviceTest;

0
投票

感谢所有提供帮助的人。我已经找到了解决方案,所以我将它发布给将来需要此帮助的任何人。

TL; DR - 答案是:

var allTests = context.DeviceTests
    .Where(x =>x.Environment.TimeStamp >= searchTime)
    .Where(x =>x.Environment.TimeStamp <= endTime)
    .ToList();

对于仍在学习如何解决此类问题的其他人,下面显示了我的代码流程。

为了获得这个解决方案,我创建了一个迷你项目,并且只包含了最基本和最重要的代码,该项目被无创地称为Linq_Issues:

public class Environment
{
    public int Id { get; set; }
    public string Version { get; set; }
    public string User { get; set; }
    public string Computer { get; set; }
    public string OSVer { get; set; }
    public virtual DateTime TimeStamp { get; set; }

}

public class DeviceTest
{
    public int? Id { get; set; }
    public virtual Environment Env {get; set;}
}

public class TestContext : DbContext
{
    public TestContext() : base("name=Testing")
    {
    }
    public DbSet<Linq_Issues.Environment> Envs { get; set; }
    public DbSet<DeviceTest> DeviceTests { get; set; }
}

然后,我创建了一个新的代码第一个数据库,并在迁移中使用了以下配置。

internal sealed class Configuration : DbMigrationsConfiguration<Linq_Issues.TestContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(Linq_Issues.TestContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data.

        context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "1",
                OSVer = "Win",
                User = "Test",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 22)
            }
        });
        context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "2",
                OSVer = "Linux",
                User = "Ted",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 23)
            }
        }); context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "1",
                OSVer = "Win",
                User = "Bill",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 24)
            }
        }); context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "1",
                OSVer = "Win",
                User = "Ted",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 25)
            }
        }); context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "2",
                OSVer = "Linux",
                User = "Bill",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 26)
            }
        }); context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "2",
                OSVer = "Linux",
                User = "Bill",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 28)
            }
        }); context.DeviceTests.AddOrUpdate(new DeviceTest
        {
            Env = new Linq_Issues.Environment
            {
                Computer = "2",
                OSVer = "Linux",
                User = "Jill",
                Version = "1",
                TimeStamp = new DateTime(2018, 1, 31)
            }
        });
    }
}

然后我可以自由地开始试验。我将我想要实现的内容分解为我能想到的最小块。这开始于让Linq只是比较一个确切的日期。所以在主方法(我使用控制台应用程序进行测试)的一面,我尝试了以下内容:

var test = context.DeviceTests
    .Where(x => x.Env.TimeStamp == new DateTime(2018, 1, 23)).ToList();

确保Linq查询的日期与我的数据库种子方法中的一个数据点完全匹配。该查询返回了一个设备对象的列表,该列表与我期望看到的完全匹配。接下来,我试图让所有日期都大于此:

var test = context.DeviceTests
    .Where(x => x.Env.TimeStamp >= new DateTime(2018, 1, 23)).ToList();

这也有效,将列表中所有匹配的设备对象返回给我。所以我接着尝试了相反的事情。

var test = context.DeviceTests
    .Where(x => x.Env.TimeStamp <= new DateTime(2018, 1, 23)).ToList();

再一次有效。因此,为了理智,我检查了我的原始解决方案是否有效。

var test = context.DeviceTests
    .Where(x => x.Env.TimeStamp >= new DateTime(2018, 1, 23) 
    && x.Env.TimeStamp <= new DateTime(2018, 1, 26)).ToList();

不出所料,它没有用。

所以使用橡皮鸭方法。我在办公桌上向我的机器人玩具解释说它击中了我。我的原始解决方案是(英文)“其中时间戳等于或小于搜索日期,时间戳等于或大于结束日期”。但是当我大声说出来时:“时间戳等于或小于搜索日期,时间戳等于或大于结束日期”。

所以我试了一下:

var tests = context.DeviceTests
    .Where(x =>x.Env.TimeStamp >= new DateTime(2018, 1, 23))
    .Where(x =>x.Env.TimeStamp <= new DateTime(2018, 1, 26))
    .ToList();

它工作并返回了我正在寻找的对象列表。然后我在我的主项目中进行了测试,它也有效!

我相信EF非核心6的Linq-to-entities不喜欢包含逻辑运算符的Where语句。我还没有找到证明这一点的文档。如果我找到文档,我会在这里发布一个链接。

© www.soinside.com 2019 - 2024. All rights reserved.