简体   繁体   English

LINQ中的匿名类型

[英]Anonymous Type in LINQ

I'm trying to get anonymous object from query: 我正试图从查询中获取匿名对象:

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()
             };

I would like name to have r.Name value cause I expect that name list contains only one element. 我希望名称有r.Name值因为我希望名称列表只包含一个元素。 If it contains 0 elements I would like name to have value NONE if more then 1 element then exception should be thrown or something. 如果它包含0个元素,我想命名为NONE,如果超过1个元素则应抛出异常或其他东西。

Is it even possible to achieve something like that? 是否有可能实现这样的目标? Thanks for help. 感谢帮助。

Instead of .ToList() use 而不是.ToList()使用

.SingleOrDefault() ?? (td.a == 0 ? "XNone" : "None")

Edit: Changed anwer based on comment. 编辑:根据评论更改了anwer。

Also I would recomend not to put such logic into Linq-to-SQL. 另外,我建议不要将这样的逻辑放入Linq-to-SQL中。 Sometimes this can result in big chunk of highly-unoptimized SQL code and, unless you dont mind some performance isues, can result in much slower SQL execution. 有时这会导致大量高度未经优化的SQL代码,除非你不介意一些性能问题,否则会导致SQL执行速度慢得多。

You can achieve that using SingleOrDefault and a temporary variable within the expression. 您可以使用SingleOrDefault和表达式中的临时变量来实现。 Something like this: 像这样的东西:

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"
};

Update: instead of presenting almost the same solution as @Euphorics answer , I've restructured the code a bit. 更新:我没有提供与@Euphorics答案几乎相同的解决方案, 而是重新构建了一些代码。 I often find nested LINQ expressions making things less readable. 我经常发现嵌套的LINQ表达式使得可读性降低。 Converting comprehension syntax into call chains could improve that. 将理解语法转换为调用链可以改善这一点。

Update 2: with some added requirements, the following select should do the trick: 更新2:有一些额外的要求,以下select应该做的伎俩:

select new
{
    a = td.a,
    b = td.b,
    c = td.c,
    name = nameValue ?? (td.a == 0 ? "XNone" : "None")
};

Theoretically you CAN'T. 从理论上讲,你不能。

Unless you have a type from where you could inspect lambda properties. 除非你有一个类型,你可以从中检查lambda属性。

The trick is to convert your anonymous object to json and deserialize it into a known type that you must have in advance. 诀窍是将您的匿名对象转换为json并将其反序列化为您必须提前拥有的已知类型。

Caution working with EF core because your linq query will be executed CLIENT side!!. 谨慎使用EF核心,因为您的linq查询将在CLIENT端执行!!

That means that all the records will be retrieved from your dbset and evaluate on client. 这意味着将从您的dbset中检索所有记录并在客户端上进行评估。

Do NOT use code like this on EF dbset iquerables. 不要在EF dbset iquerables上使用这样的代码。

Any away I will copy some extensions methods code to do it so. 我会复制一些扩展方法代码来做到这一点。

Having a defined type like... 有一个像...这样的定义类型

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Extension convert any object to json string... 扩展将任何对象转换为json字符串...

public static class ObjectExtensions
{
    public static string ToJson(this object source)
    {
        return JsonConvert.SerializeObject(source, Formatting.None);
    }
}

Extension convert any json string to typed object... 扩展将任何json字符串转换为类型对象...

public static class StringExtensions
{
    public static T FromJson<T>(this string source) where T : class
    {
        return JsonConvert.DeserializeObject<T>(source);
    }
}

Some xUnit Test 一些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.");
}

Once again... let me say that if you are querying anonymous in memory object it could be ok, but be very cautious if your iquerable cames from EF core, since client side evaluation will happen. 再一次......让我说如果你在内存对象中查询匿名它可能没问题,但是如果你的equerable来自EF核心会非常谨慎,因为客户端评估会发生。

Please enable throw exception warning when client side evaluation happens on your EF core code thought your DbContextOptionsBuilder, to prevent EF Core of executing client side evaluation code. 当您的EF核心代码考虑到您的DbContextOptionsBuilder时,请启用抛出异常警告,以防止EF Core执行客户端评估代码。 You could do it follows.. 你可以这样做..

            builder.UseSqlServer(connection, sql =>
                {
                    sql.EnableRetryOnFailure();
                    sql.MigrationsAssembly(assembly);
                })
                .UseQueryTrackingBehavior(track ? QueryTrackingBehavior.TrackAll : QueryTrackingBehavior.NoTracking)
                .ConfigureWarnings(w => w.Throw(RelationalEventId.QueryClientEvaluationWarning));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM