我有以下对象:
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查询的问题我认为问题现在已经存在于其他地方了。任何要观察的区域都会受到赞赏。
答案 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语句。我还没有找到验证这一点的文档。如果我找到文档,我会在这里发布一个链接。