LINQPad 4 for testing BPM queries?


(Haso Keric) #41
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

(Bart Elia) #42

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…


(Caleb Grundmeier) #43

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.


(Erik Johnson) #44

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 :).


(Chris Conn) #45

@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


(Caleb Grundmeier) #46

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?


(Erik Johnson) #47

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.


(Caleb Grundmeier) #48

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.

https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/clr-method-to-canonical-function-mapping

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.


(Erik Johnson) #49

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?


(Caleb Grundmeier) #50

10.2.200.6 patching this weekend to 10.2.200.10.


(Simon Hall) #51

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


(Erik Johnson) #52

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

(Caleb Grundmeier) #53

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:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/explicit-numeric-conversions-table


(Josh B) #54

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


(Haso Keric) #55

So this was for 10.2.100 maybe .200

https://www.linkedin.com/pulse/tools-epicor-linqpad-starter-kit-haso-keric/

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

(Josh B) #56

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!


(Haso Keric) #57

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


(Haso Keric) #58

(Josh B) #59

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?


(Haso Keric) #60

Press F4 and you have to add the Assemblies in.

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