Skip to content

Cannot be converted to SQL regresssion on 2.7.0 #1717

Closed
@alexey-tyulkin

Description

Code works fine on 2.6.4 and doesn't work on 2.7.0

Exception message: 
LinqToDB.Linq.LinqException : 'value(LinqToDB.Expressions.ConvertFromDataReaderExpression+ColumnReader).GetValue(ldr)' cannot be converted to SQL.


Stack trace:

Test Name:	BillingSystem.Tests.Core.PendingReturnsBusinessLayerTests.get_data
Test FullName:	BillingSystem.Tests.Core.PendingReturnsBusinessLayerTests.get_data
Test Source:	D:\src\billing-system\BillingSystem.Tests\Core\PendingReturnsBusinessLayerTests.cs : line 13
Test Outcome:	Failed
Test Duration:	0:00:02.473

Result StackTrace:	
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1089
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 831
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1069
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1766
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 1509
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSearchCondition(IBuildContext context, Expression expression, List`1 conditions, Boolean isNotExpression) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 2774
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 742
   at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.SqlBuilder.cs:line 861
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSql(IBuildContext context, Expression expression, String alias) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 490
   at LinqToDB.Linq.Builder.ExpressionBuilder.TransformExpression(IBuildContext context, Expression expr, Boolean enforceServerSide, String alias) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 358
   at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass77_0.<BuildExpression>b__0(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 52
   at LinqToDB.Expressions.Extensions.Transform(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 1353
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildExpression(IBuildContext context, Expression expression, Boolean enforceServerSide) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 52
   at LinqToDB.Linq.Builder.ExpressionBuilder.TransformExpression(IBuildContext context, Expression expr, Boolean enforceServerSide, String alias) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 230
   at LinqToDB.Linq.Builder.ExpressionBuilder.<>c__DisplayClass77_0.<BuildExpression>b__0(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 52
   at LinqToDB.Expressions.Extensions.Transform(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 1353
   at LinqToDB.Expressions.Extensions.<>c__DisplayClass34_0.<Transform>g__Modify|1(MemberBinding b) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 1500
   at LinqToDB.Expressions.Extensions.Transform2[T](ICollection`1 source, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 1321
   at LinqToDB.Expressions.Extensions.Transform(Expression expr, Func`2 func) in C:\projects\linq2db\Source\LinqToDB\Expressions\Extensions.cs:line 1546
   at LinqToDB.Linq.Builder.ExpressionBuilder.BuildExpression(IBuildContext context, Expression expression, Boolean enforceServerSide) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.QueryBuilder.cs:line 52
   at LinqToDB.Linq.Builder.SelectContext.BuildExpression(Expression expression, Int32 level, Boolean enforceServerSide) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 113
   at LinqToDB.Linq.Builder.SelectContext.BuildQuery[T](Query`1 query, ParameterExpression queryParameter) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\SelectContext.cs:line 66
   at LinqToDB.Linq.Builder.PassThroughContext.BuildQuery[T](Query`1 query, ParameterExpression queryParameter) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\PassThroughContext.cs:line 31
   at LinqToDB.Linq.Builder.PassThroughContext.BuildQuery[T](Query`1 query, ParameterExpression queryParameter) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\PassThroughContext.cs:line 31
   at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]() in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionBuilder.cs:line 161
   at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 279
   at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Query.cs:line 232
   at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache) in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 84
   at LinqToDB.Linq.ExpressionQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() in C:\projects\linq2db\Source\LinqToDB\Linq\ExpressionQuery.cs:line 179
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at 

...ReturnPremiumViewQuery.GetPendingReturnPremiumTransactions(Int32 masterId, DateTime nowDate) in ..\ReturnPremiumViewQuery.cs:line 360


Steps to reproduce

Some my code

                var query = from i in GetInternal(db, masterId, nowDate,
                            c => PendingStates.Contains(c.status) && ReturnPremiumTypes.Contains(c.type))
                            where
                                !i.HasFlag(ReturnPremiumTabFlags.MarkAsProcessed)
                                && !i.HasFlag(ReturnPremiumTabFlags.Suspended)
                                && (
                                    i.HasFlag(ReturnPremiumTabFlags.ForcePending)
                                    || (!(i.HasFlag(ReturnPremiumTabFlags.EnHolding)
                                            || i.HasFlag(ReturnPremiumTabFlags.CancelHolding))
                                        && !i.HasFlag(ReturnPremiumTabFlags.CarryForward)
                                        && i.HasFlag(ReturnPremiumTabFlags.Pending))
                                )
                            orderby i.PolicyExpirationDate, i.PolicyNumber, i.PaymentDueDate
                            select i;
                return query.ToList();

        [ExpressionMethod("HasFlagExpression")]
        public static bool HasFlag(this ReturnPremiumViewItem item, ReturnPremiumTabFlags flag) {
            throw new NotSupportedException();
        }

        public static Expression HasFlagExpression() {
            return
                (Expression<Func<ReturnPremiumViewItem, ReturnPremiumTabFlags, bool>>)
                ((t, flag) => (t.TabFlags & flag) > 0);
        }

// and internal query is

            var queryZero =
                from c in cashQuery
                join cb in db.t_ws_cash_txn_book_txn on c.id equals cb.cash_txn_id
                join b in db.t_ws_book_txn on cb.book_txn_id equals b.book_txn_id
                join bc in db.t_ws_billing_cycle on b.billing_cycle_id equals bc.billing_cycle_id
                join bp in db.t_bd_base_policy on bc.base_policy_id equals bp.base_policy_id
                join a in db.t_ws_account on bp.account_id equals a.account_id
                join i in db.t_bd_insured on a.insured_id equals i.insured_id
                join crp in db.t_bd_carrier_programs on bc.carrier_program_id equals crp.id
                join cr in db.t_bd_carrier on crp.carrier_id equals cr.carrier_id
                join ga in db.t_bd_ga on crp.ga_id equals ga.master_id
                from paymentInstrument in db.t_bd_payment_instrument
                    .Where(q => q.payment_instrument_id == c.payment_instrument_id)
                    .Select(q => new PaymentInstrument() {
                        Id = q.payment_instrument_id,
                        Type = q.payment_instrument_tp_id,
                        EssentialsId = q.payment_essentials_id,
                        State = q.state
                    })
                    .DefaultIfEmpty()
                from payee in db.t_ws_cash_txn_payee
                    .Where(q => q.cash_txn_id == c.id)
                    .Select(q => new { q.payee_type })
                    .DefaultIfEmpty()
                where
                    ga.master_id == masterId
                //orderby bc.expiration_date, bc.policy_no, c.due_date
                select new {
                    cash = c,
                    cash2book = cb,
                    book = b,
                    cycle = bc,
                    policy = bp,
                    account = a,
                    insured = i,
                    program = crp,
                    carrier = cr,
                    ga = ga,
                    pay_inst = paymentInstrument,
                    payee = payee
                };


            var cf_threshold_query = GetSettingsByNameQuery(db, ProgramSettingsConsts.CARRY_FORWARD_THRESHOLD);

            var rp_holding_threshold_query = GetSettingsByNameQuery(db, ProgramSettingsConsts.RP_HOLDING_THRESHOLD);

            var pending_rp_amount_threshold_query = GetSettingsByNameQuery(db, ProgramSettingsConsts.PENDING_RP_AMOUNT_THRESHOLD);


            var query =
                from f in queryZero
                from th in cf_threshold_query
                    .Where(t => t.carrier_program_id == f.program.id)
                    .Select(t => t.value)
                    .Distinct()
                    .Where(t => ISNUMERIC(t) == 1)
                    .Select(t => new { exp_threshold = Sql2.ConvertTo<int>.From(t) })
                    .Distinct()
                    .Take(1)
                    .DefaultIfEmpty()
                from thrp in rp_holding_threshold_query
                    .Where(t => t.carrier_program_id == f.program.id)
                    .Select(t => t.value)
                    .Distinct()
                    .Where(t => ISNUMERIC(t) == 1)
                    .Select(t => new { rp_threshold = Sql2.ConvertTo<int>.From(t) })
                    .Distinct()
                    .Take(1)
                    .DefaultIfEmpty()
                from prath in pending_rp_amount_threshold_query
                    .Where(t => t.carrier_program_id == f.program.id)
                    .Select(t => t.value)
                    .Distinct()
                    .Where(t => ISNUMERIC(t) == 1)
                    .Select(t => new { pr_amont_threshold = Sql2.Abs(Sql2.ConvertTo<int>.From(t)) })
                    .Distinct()
                    .Take(1)
                    .DefaultIfEmpty()
                let p_t = f.pay_inst != null
                        ? f.pay_inst.Type
                        : (((f.payee != null ? f.payee.payee_type : Payee.Producer) == Payee.Producer)
                            ? PaymentInstrumentType.AgencyEft
                            : PaymentInstrumentType.GACheck)
                let diffNowUntilExpirationDate =
                    Sql2.AsSql(Sql2.DateDiff(Sql2.DateParts.Day, now, f.cycle.expiration_date))
                let diffNowUntilDue =
                    Sql2.AsSql(Sql2.DateDiff(Sql2.DateParts.Day, now, f.cash.due_date))
                let is_pending = diffNowUntilDue <= 0 // now >= cash due date
                let is_force_pending = (f.cash.settings & CashTransactionSettings.DisplayAsPendingInReturnPremiumPage) > 0
                let is_force_processed = (f.cash.settings & CashTransactionSettings.MarkForProcessedInReturnPremiumPage) > 0
                let is_carry_forward = CarryForwardTypes.Contains(f.cash.type)
                    && (th != null && diffNowUntilExpirationDate >= 0
                        && diffNowUntilExpirationDate < th.exp_threshold)
                let is_force_carry_forward = (f.cash.settings & CashTransactionSettings.CarryForwardToRenewal) > 0
                let is_force_carry_forward2 = (prath == null || Sql2.Abs(f.cash.payment_amt) <= prath.pr_amont_threshold)
                let is_en_holding =
                    CarryForwardTypes.Contains(f.cash.type)
                    && thrp != null
                    && ((is_carry_forward && diffNowUntilExpirationDate < 0
                            && Sql2.Abs(diffNowUntilExpirationDate) < thrp.rp_threshold)
                        || (!is_carry_forward
                        && (diffNowUntilDue > 0)
                        /*&& diffNowUntilDue <= 0 && Sql.Abs(diffNowUntilDue) < thrp.rp_threshold*/))
                    && (prath == null || Sql2.Abs(f.cash.payment_amt) > prath.pr_amont_threshold)
                let is_cn_holding =
                    (f.cash.type == CashTransactionType.CancellationReturnPremium
                        || f.cash.type == CashTransactionType.Refund)
                    && thrp != null
                    && (diffNowUntilDue > 0)
                    //&& (diffNowUntilDue <= 0 && Sql.Abs(diffNowUntilDue) < thrp.rp_threshold)
                    && (prath == null || Sql2.Abs(f.cash.payment_amt) > prath.pr_amont_threshold)
                let is_suspended = f.cash.status == CashTransactionState.Suspended
                select new ReturnPremiumViewItem {
                    Id = f.cash.id,
                    IsSuspended = f.cash.status == CashTransactionState.Suspended,
                    IsPending = f.cash.status == CashTransactionState.Pending,
                    IsProcessed = f.cash.status == CashTransactionState.Processed,
                    IsCleared = f.cash.status == CashTransactionState.Cleared,
                    TransactionDate = f.cash.date_started,
                    PolicyNumber = f.cycle.policy_no,
                    ProducerCode = f.cycle.producer_cd,
                    Producer = new Producer {
                        ProducerCode = f.cycle.producer_cd,
                        PCProducerAppointmentId = f.cycle.pc_appointment_id
                    },
                    Type = f.cash.type,
                    State = f.cash.status,
                    PaymentDueDate = f.cash.due_date,
                    SettledDate = f.cash.date_settled,
                    ClearedDate = f.cash.date_cleared,
                    RpAmount = f.cash.payment_amt,
                    PaymentInstrument = f.pay_inst,
                    PaymentInstrumentType = p_t,
                    Payee = f.payee != null ? f.payee.payee_type : Payee.Producer,
                    IsPay = (f.cash.settings & CashTransactionSettings.DisplayAsPendingInReturnPremiumPage) > 0,
                    SuspensionReason = f.cash.suspense_reason.ToString(),
                    SuspensionNotes = f.cash.suspense_notes,
                    SettlementDetails = f.cash.settlement_details,
                    Settings = f.cash.settings,
                    PolicyExpirationDate = f.cycle.expiration_date,
                    ProgramName = f.program.name,
                    ProgramId = f.program.id,

                    CarryForwardThresholdSetting = th.exp_threshold,
                    RpHoldingThresholdSetting = thrp.rp_threshold,
                    PendingRpAmountThreshold = prath.pr_amont_threshold,
                    DiffNowUntilExpirationDate = diffNowUntilExpirationDate,
                    DiffNowUntilDue = diffNowUntilDue,
                    TabFlags = Sql2.AsSql(
                              GetFlag(is_pending, ReturnPremiumTabFlags.Pending)
                            | GetFlag(is_force_pending, ReturnPremiumTabFlags.ForcePending)
                            | GetFlag(is_force_processed, ReturnPremiumTabFlags.MarkAsProcessed)
                            | GetFlag(is_carry_forward, ReturnPremiumTabFlags.CarryForward)
                            | GetFlag(is_force_carry_forward, ReturnPremiumTabFlags.CarryForward)
                            | GetFlag(is_force_carry_forward2, ReturnPremiumTabFlags.CarryForward)
                            | GetFlag(is_en_holding, ReturnPremiumTabFlags.EnHolding)
                            | GetFlag(is_cn_holding, ReturnPremiumTabFlags.CancelHolding)
                            | GetFlag(is_suspended, ReturnPremiumTabFlags.Suspended)
                            ),
                    BillingCycleId = f.cycle.billing_cycle_id,
                    MasterId = f.ga.master_id,
                    InsuredId = f.insured.insured_id,
                    InsuredName = f.insured.first_name + " " + f.insured.last_name,
                    HasMortgageePayments = Sql2.AsSql(HasMortgageePaymentsValue(db, f.cycle))

                };

Generate expression test does not collect test, see output below.

System.NullReferenceException
Object reference not set to an instance of an object.
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.MangleName(String name, String prefix) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 684
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.<>c__DisplayClass11_0.<BuildType>b__7(ParameterInfo p) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 542
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.<>c__DisplayClass11_0.<BuildType>b__1(ConstructorInfo c) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 542
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.BuildType(Type type) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 530
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.GenerateSourceString(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 911
   at LinqToDB.Linq.Builder.ExpressionTestGenerator.GenerateSource(Expression expr) in C:\projects\linq2db\Source\LinqToDB\Linq\Builder\ExpressionTestGenerator.cs:line 884

Environment details

linq2db version: 2.7.0
Database Server: Sql Server 2016
Operating system: Windows 10
Framework version: .NET Framework 4.7.1

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions