代码之家  ›  专栏  ›  技术社区  ›  Konstantin Konstantinov

如何使用表达式在Linq Select New中分配属性

  •  1
  • Konstantin Konstantinov  · 技术社区  · 7 年前

    在一般类中,我有以下情况:

    IQueryable<TQuote> query = GetQuotes(ctx)
    

    哪里 ctx 是数据库上下文,并且 GetQuotes 收益率 DbSet<TQuote> .

    然后在代码下面的某个地方执行查询。其简化形式如下:

    var list = await query
        .Select(v => new
        {
            v.Id,
            TimeZone = v.Property != null ? (int?)v.Property.TimeZone : null
            // and about 10 more simple properties like v.Id above
        }
        .ToListAsync();
    

    哪里 Property 是导航属性(到另一个表),并且 TimeZone 只是类型的常规数据库列/属性 int? 在C语言中。

    在我尝试将该泛型类与不具有导航属性的实体一起使用之前,所有操作都有效。 财产 . 所以,我想替换“硬编码”表达式 v.Property != null ? (int?)v.Property.TimeZone : null 通过类的抽象成员,然后针对不同的 TQuote 类型。

    我试过用这个签名:

    protected abstract Expression<Func<TQuote, int?>> GetTimeZone();
    

    但是,如果我在LINQ中使用它(直接使用或先分配给某个变量),然后签名 时区 也改变为 Expression<...> 如果我尝试 ...Compile().Invoke(v) 然后Linq抱怨Linq to实体不支持这一点。

    我看到了这个答案: Create a Dynamic Linq to EF Expression to Select IQueryable into new class and assign properties 然而,它用手构建了整个选择器,并且假设我总共有16个属性,这将是一个颈部疼痛的创建和维护。所以,我想知道我能不能做点什么 时区 只不过将其余部分保留为上述简单的LINQ形式。

    有可能吗?如果有,具体情况如何?

    1 回复  |  直到 7 年前
        1
  •  1
  •   michael yin    7 年前

    试试Nuget Linqkit, https://github.com/scottksmith95/LINQKit .

    下面是我的尝试。 Linqkit提供 AsExpandable() Invoke(v) 方法。 我编造了像 Area.TimeZone Region.RegionalTimeZone .

    using LinqKit;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    
    class QuoteResult
    {
        public int Id { get; set; }
        public int? TimeZone { get; set; }
        public string Note { get; set; }
    }
    
    abstract class QuoteHelper<TQuote> where TQuote : Quote
    {
        protected abstract Expression<Func<TQuote, int?>> GetTimeZone { get; }
    
        public IEnumerable<QuoteResult> GetQuoteResults(
            EfExpressionPropertyDbContext ctx)
        {
            IQueryable<TQuote> query = GetQuotes(ctx);
            var getTimeZone = GetTimeZone;
    
            var list = query
                .AsExpandable()
                .Select(v => new QuoteResult
                {
                    Id = v.Id,
                    TimeZone = getTimeZone.Invoke(v),
                    Note = v.Note
                    // and about 10 more simple properties like v.Id above
                })
                .ToList();
            return list;
        }
    
        public IQueryable<TQuote> GetQuotes(
            EfExpressionPropertyDbContext ctx)
        {
            return ctx.Set<TQuote>();
        }
    }
    
    class CommonQuoteHelper : QuoteHelper<CommonQuote>
    {
        protected override Expression<Func<CommonQuote, int?>> GetTimeZone
        {
            get { return q => q.Area != null ? (int?)q.Area.TimeZone : null; }
        }
    }
    
    class PeculiarQuoteHelper : QuoteHelper<PeculiarQuote>
    {
        protected override Expression<Func<PeculiarQuote, int?>> GetTimeZone
        {
            get { return q => q.Region != null ? (int?)q.Region.RegionalTimeZone : null; }
        }
    }