我正在尝试从查询中获取匿名对象:
var myList = from td in MyObjectList
select new
{
a = td.a,
b = td.b,
c = td.c,
name = (from r in contex.NewList
where r.aa == td.a && r.bb == td.b
select r.Name).ToList()
};
我想将名称设为r.Name值因为我希望名称列表只包含一个元素。如果它包含0个元素,我想命名为NONE,如果超过1个元素则应该抛出异常或其他东西。
甚至有可能实现这样的目标吗?谢谢你的帮助。
答案 0 :(得分:7)
而不是.ToList()
使用
.SingleOrDefault() ?? (td.a == 0 ? "XNone" : "None")
编辑:根据评论更改了答案。
另外,我建议不要将这样的逻辑放入Linq-to-SQL中。有时这会导致大量高度未经优化的SQL代码,除非你不介意一些性能问题,否则会导致SQL执行速度慢得多。
答案 1 :(得分:2)
您可以使用SingleOrDefault
和表达式中的临时变量来实现。像这样:
var myList =
from td in MyObjectList
let nameValue = contex.NewList
.Where(r => r.aa== td.a && r.bb == td.b)
.Select(r => r.Name)
.SingleOrDefault()
select new
{
a = td.a,
b = td.b,
c = td.c,
name = nameValue ?? "NONE"
};
更新:而不是提供与@Euphorics answer几乎相同的解决方案,我重新构建了一些代码。我经常发现嵌套的LINQ表达式使得可读性降低。将理解语法转换为调用链可以改善这一点。
更新2:并增加了一些要求,以下select
应该可以解决问题:
select new
{
a = td.a,
b = td.b,
c = td.c,
name = nameValue ?? (td.a == 0 ? "XNone" : "None")
};
答案 2 :(得分:0)
理论上你不能。
除非您有可以从其中检查lambda属性的类型。
诀窍是将匿名对象转换为json并将其反序列化为事先必须具有的已知类型。
使用EF内核时要小心,因为您的linq查询将在客户端执行!!
这意味着将从您的dbset中检索所有记录并在客户端上进行评估。
请勿在EF dbset可查询对象上使用此类代码。
无论如何,我都会复制一些扩展方法代码来做到这一点。
具有定义的类型,例如...
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
扩展将任何对象转换为json字符串...
public static class ObjectExtensions
{
public static string ToJson(this object source)
{
return JsonConvert.SerializeObject(source, Formatting.None);
}
}
扩展将任何json字符串转换为键入的对象...
public static class StringExtensions
{
public static T FromJson<T>(this string source) where T : class
{
return JsonConvert.DeserializeObject<T>(source);
}
}
一些xUnit测试
[Fact]
public void AddSelectTest()
{
var data = new[]
{
new {Id = 01, Name = "Engineering", GroupName = "Engineering and Development"},
new {Id = 02, Name = "Tool Design", GroupName = "Tool Design and Research"},
new {Id = 03, Name = "Sales", GroupName = "Sales and Marketing"},
new {Id = 04, Name = "Marketing", GroupName = "Marketing and Sales"},
new {Id = 05, Name = "Purchasing", GroupName = "Inventory Management"},
new {Id = 06, Name = "Research and Development", GroupName = "Development and Research"},
new {Id = 07, Name = "Production", GroupName = "Manufacturing and Production"},
new {Id = 08, Name = "Production Control", GroupName = "Control and Production"},
new {Id = 09, Name = "Human Resources", GroupName = "Human Resources and Administration"},
new {Id = 10, Name = "Finance", GroupName = "Finance and Executive General"},
new {Id = 11, Name = "Information Services", GroupName = "Information Services and Administration"},
new {Id = 12, Name = "Document Control", GroupName = "Document Control and Quality Assurance"},
new {Id = 13, Name = "Quality Assurance", GroupName = "Administration and Quality Assurance"},
new {Id = 14, Name = "Facilities and Maintenance", GroupName = "Maintenance and Facilities"},
new {Id = 15, Name = "Shipping and Receiving", GroupName = "Receiving and Shipping"},
new {Id = 16, Name = "Executive", GroupName = "Executive General and Administration"}
};
var queryable = data.AsQueryable();
var first = queryable.Select(d => new { Id = d.Id, Name = d.Name }).FirstOrDefault(d => d.ToJson().FromJson<Department>().Id == 1);
Assert.True(first != null, "Expected a department value but 'null' was found.");
}
再一次...让我说一次,如果您要查询内存对象中的匿名对象就可以了,但是如果您的可查询性来自EF核心,则要非常小心,因为将会进行客户端评估。
请以DbContextOptionsBuilder为基础,在EF核心代码上进行客户端评估时启用抛出异常警告,以防止EF Core执行客户端评估代码。您可以按照以下步骤进行。
builder.UseSqlServer(connection, sql =>
{
sql.EnableRetryOnFailure();
sql.MigrationsAssembly(assembly);
})
.UseQueryTrackingBehavior(track ? QueryTrackingBehavior.TrackAll : QueryTrackingBehavior.NoTracking)
.ConfigureWarnings(w => w.Throw(RelationalEventId.QueryClientEvaluationWarning));