2

Error:

I'm getting the error mentioned above and the following is my stack trace:

Unable to create a constant value of type 'JackHenry.JHAKeys.Model.ADSENTDB.L_FORMS_SEL_APPLICANT'. Only primitive types or enumeration types are supported in this context.

Source: "mscorlib"

at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.WaitAll(Task[] tasks, Int32 millisecondsTimeout) at System.Threading.Tasks.Task.WaitAll(Task[] tasks) at Keys.BusinessLogic.Lending.Document.Fill.LoanFillService.FillLoanObject(String workID, Boolean documentSelection) in F:\JHA6\JHAKEYS\2018\Services\DEV\ArgoServices\Keys.BusinessLogic\Lending\Document\Fill\LoanFillService.cs:line 422

I've narrowed my problem down to the following linq statement:

var query = from t in ctx.L_FORMS_SELECTION
            where (ctx.L_FORMS_SEL_APPLICANT.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_APP_INSIDER.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_PROD_CODE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_PROD.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_QUEUE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_COLLAT.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_COLLAT_STATE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_COLLAT_VIEW.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_LOAN.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_LOAN_JURISDICTION.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_LOAN_PURPOSE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_REG.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_SUBSTITUTE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_CREDIT_INS.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_APP_MARITAL_STAT.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_APP_STATE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_RATE.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_COLLAT_COUNTY.Any(c => (c.form_id == t.form_id)) ||
            ctx.L_FORMS_SEL_LOAN_APPSOURCE.Any(c => (c.form_id == t.form_id)))
            && t.shared_service_ind.ToUpper().Trim() == "E"
            select t;

if ((query.FirstOrDefault() != null))
                    return true;

Obviously just trying to search through a bunch of tables to see if the value exists in any of them.

Background:

I understand that its looking for a primitive (i.e. guid), but I'm not sure how to work that into an effective linq statement. I searched through SO and found many articles discussing a similar issue. However, I either do not understand fully the problem or how those solutions can be interpreted correctly for my issue.

This query worked fine when running in VS 2013. The problem is only occurring in VS 2015. I'm using .Net framework 4 and Entity Framework 5 (version 4.4). I was using a license of ReSharper, but have since turned it off. I'm not sure if I'm missing a configuration or not synching up correctly. I've of course looked and all seems to be fine...not sure why visual studio 2015 is acting up?

I've also recreated the workspace and rebuilt with VS 2015 just to make sure that VS 2013 wasn't caching something somewhere.

Trials

I've simplified the problem to only 2 tables and the following query gives me this error also:

var tmp2 = from t in ctx.L_FORMS_SELECTION
           where ctx.L_FORMS_SEL_APPLICANT.Any(c => (c.form_id == t.form_id))
           select t;
if ((tmp2.FirstOrDefault() != null))
    return true;

After some more simplification I ended up with a working query. This one contains the two tables above plus a third one for illustration:

var tmp3 = from frmSel in ctx.L_FORMS_SELECTION
           join frmApp in ctx.L_FORMS_SEL_APPLICANT on frmSel.form_id equals frmApp.form_id
           join ins in ctx.L_FORMS_SEL_APP_INSIDER on frmSel.form_id equals ins.form_id
           select t3;
if ((tmp3.FirstOrDefault() != null))
    return true;

So this is better, but I need to combine 20 tables...not just 3. I could do a lot of joins but wouldn't this approach be less efficient and create more overhead? Also, I'm still not sure why the original query works in VS 2013 but not VS 2015 - maybe I just need to focus on that and not spend effort on refactoring the query?

Since the query didn't blow up, I expanded on it and just recreated my original query but this time using the 'join' keyword:

var tmp4 = from t in ctx.L_FORMS_SELECTION
           join app in ctx.L_FORMS_SEL_APPLICANT on t.form_id equals app.form_id
           join appState in ctx.L_FORMS_SEL_APP_STATE on t.form_id equals appState.form_id
           join appSource in ctx.L_FORMS_SEL_LOAN_APPSOURCE on t.form_id equals appSource.form_id
           join appMarital in ctx.L_FORMS_SEL_APP_MARITAL_STAT on t.form_id equals appMarital.form_id
           join appIns in ctx.L_FORMS_SEL_APP_INSIDER on t3.form_id equals appIns.form_id
           join prodCode in ctx.L_FORMS_SEL_PROD_CODE on t.form_id equals prodCode.form_id
           join prod in ctx.L_FORMS_SEL_PROD on t.form_id equals prod.form_id
           join queue in ctx.L_FORMS_SEL_QUEUE on t.form_id equals queue.form_id
           join coll in ctx.L_FORMS_SEL_COLLAT on t3.form_id equals coll.form_id
           join collState in ctx.L_FORMS_SEL_COLLAT_STATE on t.form_id equals collState.form_id
           join collView in ctx.L_FORMS_SEL_COLLAT_VIEW on t.form_id equals collView.form_id
           join collCnty in ctx.L_FORMS_SEL_COLLAT_COUNTY on t.form_id equals collCnty.form_id
           join loan in ctx.L_FORMS_SEL_LOAN on t.form_id equals loan.form_id
           join loanJur in ctx.L_FORMS_SEL_LOAN_JURISDICTION on t.form_id equals loanJur.form_id
           join loanPur in ctx.L_FORMS_SEL_LOAN_PURPOSE on t.form_id equals loanPur.form_id
           join reg in ctx.L_FORMS_SEL_REG on t.form_id equals reg.form_id
           join sub in ctx.L_FORMS_SEL_SUBSTITUTE on t.form_id equals sub.form_id
           join credit in ctx.L_FORMS_SEL_CREDIT_INS on t.form_id equals credit.form_id
           join rate in ctx.L_FORMS_SEL_RATE on t.form_id equals rate.form_id
           where t.shared_service_ind.ToUpper().Trim() == "E"
           select t;

This one doesn't throw an error...but does not return any value either (in VS 2013). The original linq query returned a value (at least when I ran it in VS 2013) - strange.

I looked at the results of the original query (run in VS2013) and found that there is a matching form_id. I then ran a foreach query and got a match of course. It seems that for some reason my 'equal' is not working correctly - maybe this is because form_id is a Guid.

After more development...this is where I stand. This query just loops through and exits the loop immediately after a value is found. Thus I think this is more efficient, but also a little wordy and not as neat as I would like:

foreach (var rec in ctx.L_FORMS_SELECTION)
{
    var app = ctx.L_FORMS_SEL_APPLICANT.Where(c => c.form_id == rec.form_id);
     if (app.FirstOrDefault() != null) return true;

     var appState = ctx.L_FORMS_SEL_APP_STATE.Where(c => c.form_id == rec.form_id);
     if (appState.FirstOrDefault() != null) return true;

     var appSource = ctx.L_FORMS_SEL_LOAN_APPSOURCE.Where(c => c.form_id == rec.form_id);
     if (appSource.FirstOrDefault() != null) return true;

     var appMarital = ctx.L_FORMS_SEL_APP_MARITAL_STAT.Where(c => c.form_id == rec.form_id);
     if (appMarital.FirstOrDefault() != null) return true;

     var appIns = ctx.L_FORMS_SEL_APP_INSIDER.Where(c => c.form_id == rec.form_id);
     if (appIns.FirstOrDefault() != null) return true;

     var prodCode = ctx.L_FORMS_SEL_PROD_CODE.Where(c => c.form_id == rec.form_id);
     if (prodCode.FirstOrDefault() != null) return true;

     var prod = ctx.L_FORMS_SEL_PROD.Where(c => c.form_id == rec.form_id);
     if (prod.FirstOrDefault() != null) return true;

     var queue = ctx.L_FORMS_SEL_QUEUE.Where(c => c.form_id == rec.form_id);
     if (queue.FirstOrDefault() != null) return true;

     var coll = ctx.L_FORMS_SEL_COLLAT.Where(c => c.form_id == rec.form_id);
     if (coll.FirstOrDefault() != null) return true;

     var collState = ctx.L_FORMS_SEL_COLLAT_STATE.Where(c => c.form_id == rec.form_id);
     if (collState.FirstOrDefault() != null) return true;

     var collView = ctx.L_FORMS_SEL_COLLAT_VIEW.Where(c => c.form_id == rec.form_id);
     if (collView.FirstOrDefault() != null) return true;

     var collCnty = ctx.L_FORMS_SEL_COLLAT_COUNTY.Where(c => c.form_id == rec.form_id);
     if (collCnty.FirstOrDefault() != null) return true;

     var loan = ctx.L_FORMS_SEL_LOAN.Where(c => c.form_id == rec.form_id);
     if (loan.FirstOrDefault() != null) return true;

     var loanJur = ctx.L_FORMS_SEL_LOAN_JURISDICTION.Where(c => c.form_id == rec.form_id);
     if (loanJur.FirstOrDefault() != null) return true;

     var loanPur = ctx.L_FORMS_SEL_LOAN_PURPOSE.Where(c => c.form_id == rec.form_id);
     if (loanPur.FirstOrDefault() != null) return true;

     var reg = ctx.L_FORMS_SEL_REG.Where(c => c.form_id == rec.form_id);
     if (reg.FirstOrDefault() != null) return true;

     var sub = ctx.L_FORMS_SEL_SUBSTITUTE.Where(c => c.form_id == rec.form_id);
     if (sub.FirstOrDefault() != null) return true;

     var credit = ctx.L_FORMS_SEL_CREDIT_INS.Where(c => c.form_id == rec.form_id);
     if (credit.FirstOrDefault() != null) return true;

     var rate = ctx.L_FORMS_SEL_RATE.Where(c => c.form_id == rec.form_id);
     if (rate.FirstOrDefault() != null) return true;
}

Not sure if this can be done more consicely or not - its more code than the original. I hope that this is all that VS 2015 doesn't like =) Thank you for reading through this and I appreciate any guidance provided.

Frank
  • 21
  • 4
  • http://stackoverflow.com/questions/15211362/only-primitive-types-or-enumeration-types-are-supported-in-this-context – aybe Jan 19 '17 at 20:30
  • Hmm, there is no way the second query `var tmp2 = ...` to generate such exception. `L_FORMS_SELECTION` and `L_FORMS_SEL_APPLICANT` are standard `DbSet`s, right? Can you post the exception stack trace? – Ivan Stoev Jan 19 '17 at 20:36
  • @Ivan Stoev: L_FORMS_SELECTION and L_FORMS_SEL_APPLICANT are both EF tables. I've included the stack trace in the description above – Frank Jan 19 '17 at 21:08
  • 1
    What makes you think joins are less efficient than your manual workaround? – Guillaume CR Jan 19 '17 at 21:17
  • @Guillaume CR: I'm not sure...but I thought linq's joins (via the 'join' statement) involved more overhead than just searching through the tables. I'm not heavy into linq and it seems both are similar...but I thought the 'Join' statement involved more infrastructure. – Frank Jan 19 '17 at 21:23
  • For your function to return true, all the rows have to be fully joined. Only when returning false would you get theoretical perf increases by not fully joining. If false is 80% to 20% true, then maybe you have an argument to be made for optimization, but you have to measure it first. Otherwise, stick basic LINQ. – Guillaume CR Jan 19 '17 at 21:28
  • The stack trace is useless - you need to let VS break when the exception is thrown in order to get the real stack trace. Anyway, you are using too outdated EF version which I cannot test, could be a bug fixed in a later versions. Good luck. – Ivan Stoev Jan 19 '17 at 21:29
  • Now that I think about it, since you use "FirstOrDefault" I'm not sure there is any perf difference between your 2 queries. Using Join definitely lets the LINQ engine assume more about your query. I would use it. – Guillaume CR Jan 19 '17 at 21:36
  • @Ivan Stoev: I turned on the Exceptions and can see one as soon as its thrown. Is that what you're referring to? I'm seeing this in the StackTrace property - at System.Data.Objects.ELinq.ExpressionConverter.ConstantTranslator.TypedTranslate(ExpressionConverter parent, ConstantExpression linq) – Frank Jan 19 '17 at 22:38
  • @Guillaume CR: Thanx...I've converted the linq query so it now uses 'join's instead. When running the two queries in VS 2013, the original query returns true, but my new query (with the joins) does not. – Frank Jan 19 '17 at 23:16
  • I just now realized that your original query has OR instead of AND. Join is an AND operation. I apologize for leading you in error. Just to be clear, you require that your function return true iff any L_FORMS_SELECTION rows have shared_service_ind == 'E' AND form_id exists in at least 1 of the other tables. Is that correct? I will try to cook up a proper LINQ, but you may want to consider using a lot of foreach. I've found that helps simplify the problem to pinpoint the error. I'm still not clear why LINQ needs to convert your tables to constants. – Guillaume CR Jan 20 '17 at 15:58
  • @Guillaume CR: You are correct that I only want a result back if the main table's (L_FORMS_SELECTION) form_id matches at least one of those other tables' form_id. Also, why do you think the original query works in vs2013 but not vs2015? Nothing has changed - same .Net framework and same entity framework. – Frank Jan 20 '17 at 18:43
  • This seems related to [this issue](http://stackoverflow.com/questions/18929483/unable-to-create-a-constant-value-of-type-only-primitive-types-or-enumeration-ty) although I don't know why that stopped working. Consider submitting a bug to [Microsoft Connect](https://connect.microsoft.com/) . At the very least, the error message is rather unclear and not helpful. Also, consider updating to the latest .Net and EF. They may already have fixed the issue. – Guillaume CR Jan 23 '17 at 14:34
  • We are looking to upgrade to .Net Framework 4.6.2 really soon...then hopefully to EF 6. Thanx again for the help – Frank Jan 23 '17 at 17:30
  • I've racked my brain over the query, and ultimately your original query is what I end up with. It should work. Good luck out there and sorry we couldn't figure it out! – Guillaume CR Jan 23 '17 at 19:22

0 Answers0