LINQPad 4 for testing BPM queries?

Stuff like this EF4: 
System.Data.Objects.SqlClient.SqlFunctions.StringConvert((decimal)asm).Trim()

Moved to EF6:
System.Data.Entity.SqlServer.SqlFunctions // StringConvert, DateDiff...
System.Data.Entity.DbFunctions // For EF Functions like AddDays or TruncateTime

References as Bart wrote:

  • EntityFramework.dll
  • EntityFramework.SqlServer.dll
1 Like

var q2 = Db.UD13.Select(s =>
new { Company = s.Company, OrderNum = Convert.ToInt32(s.Key1),
OrderLine = Convert.ToInt32(s.Key2),
OrderRelNum = Convert.ToInt32(s.Key3) }).ToList()
ā€¦

Hmmm something not smelling right. Like a using is missing. Let me play tomorrow if I have a chanceā€¦

1 Like

I think I found the missing piece: Erp.ErpEFFunctions instead of the standard .Net Convert.ToInt32. Using the Epicor methods to do the conversions seem to work without having to use that AsEnumerable extension.

var q = Db.UD13.Select(s =>
    new
    {
        Company = s.Company,
        OrderNum = Erp.ErpEFFunctions.ConvertToInt(s.Key1),
        OrderLine = Erp.ErpEFFunctions.ConvertToInt(s.Key2),
        OrderRelNum = Erp.ErpEFFunctions.ConvertToInt(s.Key3)
    }).ToList();

The other problem I found with LinqPad is UD fields. I donā€™t know how to use them yet. In Visual Studio or the BPM, it will compile while using syntax like s.MyUDField. That didnā€™t fly in LinqPad. Using syntax like s[ā€œMyUDFieldā€] also didnā€™t work. So that is the next investigation. Probably another reference problem.

The goal Iā€™m trying to get at is to be able to write the query in LinqPad and not have to do any extra editing when pasting into a BPM.

2 Likes

Entity Framework does not have translations to every .NET function, so we had to register some of our own.

The reason casting to AsEnumerable() worked is that a delegate call gets inserted that executes *before * the Select() call. So, EF will do a SELECT * FROM UD13 and fetch all the data ā€“ and all 100+ columns ā€“ before calling the Select() function, which then just re-materializes the data into the anonymous type.

Using ErpEFFunctions.ConvertToInt allows EF to make the T-Sql query match the structure of the anonymous type ā€“ with just four columns appearing in the SQL SELECT statement. Itā€™s way more efficient.

BTW, the ErpEFFunctions.ConvertToInt function basically does thisā€¦

[System.Data.Entity.DbFunction(ā€œEpicorDBā€, ā€œConvertToIntā€)]

public
static
int ConvertToInt(string
val)

    {

        return Int32.TryParse(val, out Int32 result) ? result : default;

   }

ā€¦ Iā€™m not sure why we didnā€™t call Convert.ToInt32() under the hood. Oh, and I wish the actual code was this compact :).

5 Likes

@erikj if no one has mentioned it lately, we appreciate your presence and input here on the forum, as we do all epicor insiders, consultants and knowledgeable users!

[System.Data.Entity.DbFunction(ā€œEpicorDBā€, ā€œConvertToIntā€)]

public static int ConvertToInt(string val)
    {
        return Int32.TryParse(val, out Int32 result) ? result : default;
   }

Here is how to format c# code on the forum
image

2 Likes

Are you saying we can create our own conversion functions(As long as we add it as a reference)? Or are you just pointing out what the ErpEFFFunction does?

1 Like

I was just pointing out what the ErpEFFunction does (which was nothing magic). These functions are baked into the Erp model (which is what the docs said to do) and Iā€™m not sure EF will recognize functions declared outside the model. But Iā€™ll play with it and see what happens.

1 Like

I was unsuccessful in my attempt create my own functions that worked. I did find a resource, which may be useful for others if they need to know what .Net methods will work out of the box.

However, there doesnā€™t seem to be any methods that convert decimals to integers. Since the UD tables donā€™t have integer fields, projecting the Decimal fields to an Integer field in an anonymous type is pretty ugly and not intuitive.

Erp.ErpEFFunctions.ConvertToInt(SqlFunctions.StringConvert((decimal)decimalvalue))

versus something simple like

Convert.ToInt32(decimalvalue)

And just to be clear, this concerns Linq to Entities. Once the records are in memory, Linq to Objects takes over and type conversions are not an issue.

1 Like

I can see about getting a function added to the model for converting decimals to ints. But it probably wouldnā€™t be backported very far. What version are you on?

1 Like

10.2.200.6 patching this weekend to 10.2.200.10.

1 Like

I second those remarks from Chris. Thanks for your input Erik.

2 Likes

A smart guy in our Birmingham, UK office reminded me that decimal has an intrinsic cast to int, which is supported by EF. Strings canā€™t be cast to ints, which is why we have the helper functions. But this should workā€¦

var q = Db.UD13.Select(s =>
    new
    {

        MyNumber = (int)s.Number01
    }).ToList();
1 Like

By golly youā€™re right. I thought I tried that but apparently not. Much simpler. I canā€™t believe that I didnā€™t find that in all my googling.

Iā€™ll share this link for valid numeric casts:

1 Like

Hi Caleb,

Iā€™m using Epicor 10.2.200 and Iā€™m trying to mock up and instantiate an instance of the ErpContext. I have all but the Epicor.Data.Provider reference. I tried locating it inside the Assemblies folder on the machine Epicor is installed on, but no luck.

Do you know where else I can find it? I keep getting that " *o Entity Framework provider found for the ADO.NET provider with invariant name ā€˜EpiProviderā€™." error message like you were getting.

Thanks,

Josh

1 Like

So this was for 10.2.100 maybe .200

It might be instead of EpiProviderRegistration - It may be EpiProviderRegistrator ( i may even have it incorrect in the article )

Change:
// Enable for 10.2 Only: EpiProviderRegistration.Register();
for the following:
// Enable for 10.2 Only: EpiProviderRegistrator.Register();
2 Likes

I think I just got it.

Looks like it accepts:
Epicor.Data.Provider.EpiProviderRegistrator.Register();

That ADO error went away once I added this in.

Thanks!

2 Likes

Also check the LinkedIn Article :slight_smile: I need to convert it to Markdown and paste here.

1 Like
3 Likes

Have you ever had the need to instantiate a quote service (shown below)?

Erp.Contracts.QuoteSvcContract quote = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.QuoteSvcContract>(context);

It keeps giving me the error ā€œUnable to find assembly for contract Erp.Contracts.QuoteSvcContractā€.

The context instantiates fine, why wouldnā€™t the service?

1 Like

Press F4 and you have to add the Assemblies in.

In your case Erp.Contracts.QuoteSvcContract preferrably from within your Epicor Client Directory.

1 Like