其中NavigationProperty.date> = Date,即使数据库具有有效数据

时间:2018-03-01 11:43:57

标签: c# entity-framework linq

我有以下对象:

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查询的问题我认为问题现在已经存在于其他地方了。任何要观察的区域都会受到赞赏。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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();

不出所料,它不起作用。

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

所以我试了一下:

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语句。我还没有找到验证这一点的文档。如果我找到文档,我会在这里发布一个链接。