我正在尝试从查询中获取匿名对象:
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()
};
我希望 name 具有 r.Name 值,因为我希望名称列表仅包含一个元素。如果它包含 0 个元素,我希望 name 的值为 NONE,如果超过 1 个元素,则应抛出异常或其他内容。
有可能实现这样的目标吗?感谢您的帮助。
代替
.ToList()
使用
.SingleOrDefault() ?? (td.a == 0 ? "XNone" : "None")
编辑:根据评论更改了答案。
我还建议不要将此类逻辑放入 Linq-to-SQL 中。有时,这可能会导致大量高度未优化的 SQL 代码,并且除非您不介意某些性能问题,否则可能会导致 SQL 执行速度慢得多。
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答案几乎相同的解决方案,我对代码进行了一些重组。我经常发现嵌套的 LINQ 表达式使内容的可读性降低。将理解语法转换为调用链可以改善这一点。
更新 2: 添加了一些要求,以下
select
应该可以解决问题:
select new
{
a = td.a,
b = td.b,
c = td.c,
name = nameValue ?? (td.a == 0 ? "XNone" : "None")
};
理论上你不能。
除非你有一个可以检查 lambda 属性的类型。
技巧是将匿名对象转换为 json 并将其反序列化为您必须提前拥有的已知类型。
使用 EF core 时请小心,因为您的 linq 查询将在客户端执行!!.
这意味着将从您的数据库集中检索所有记录并在客户端上进行评估。
不要在 EF dbset 上使用这样的代码
IQueryable
s。
无论如何,我都会复制一些扩展方法代码来做到这一点。
有一个定义的类型,例如...
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.");
}
再次...让我说,如果您在内存对象中查询匿名,那可能没问题,但如果您的
IQueryable
来自 EF Core,则要非常小心,因为将会发生客户端评估。
当您的 EF Core 代码发生客户端评估时,请启用抛出异常警告(认为您的
DbContextOptionsBuilder
),以防止 EF Core 执行客户端评估代码。你可以这样做..
builder.UseSqlServer(connection, sql =>
{
sql.EnableRetryOnFailure();
sql.MigrationsAssembly(assembly);
})
.UseQueryTrackingBehavior(track ? QueryTrackingBehavior.TrackAll : QueryTrackingBehavior.NoTracking)
.ConfigureWarnings(w => w.Throw(RelationalEventId.QueryClientEvaluationWarning));