Unable to use <entitycollection>.FindMatches with bigint column when comparing to integer

Posts   
 
    
Posts: 2
Joined: 31-Oct-2006
# Posted on: 31-Oct-2006 15:02:33   

Hi

  • Using LLBLGen Pro.version: 2.0.0.0 Final (October 3rd, 2006)
  • FileVersion of SD.LLBLGen.Pro.ORMSupportClasses.NET20.dll is 2.0.0.61005
  • FileVersion of SD.LLBLGen.Pro.DQE.SqlServer.NET20.dll is 2.0.0.60722
  • Database is a SQL Server 2000 - Service Pack 1
  • Template Group is Adapter
  • LLBL database driver is "SQLServer DBDriver (2.0.07282006)"
  • Im generating to VB.NET 2.0 (VS 2005) I have this table
CREATE TABLE [dbo].[Test] (
    [MyLongId] [bigint] IDENTITY (1, 1) NOT NULL ,
    [MyIntId] [int] NOT NULL 
) ON [PRIMARY]

with this content


MyLongId   MyIntId
1               10
2               11

I load all entities into a collection

Private ecTests As New EntityCollection(Of TestEntity)(New TestData.FactoryClasses.TestEntityFactory())

  Private Sub btnUnfiltered_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnfiltered.Click
    Using daa As New DataAccessAdapter(True)
      daa.FetchEntityCollection(ecTests, Nothing)
      daa.CloseConnection()
    End Using
  End Sub

Then this filter works (yielding 1 result)

Dim Indexes As Generic.List(Of Integer) = ecTests.FindMatches(TestFields.MyLongId = "1")

but this does not (yielding 0 results)

Dim Indexes As Generic.List(Of Integer) = ecTests.FindMatches(TestFields.MyLongId = 1)

but then this works (yielding 1 result)

Dim Indexes As Generic.List(Of Integer) = ecTests.FindMatches(TestFields.MyLongId = cLng("1"))

How come the "TestFields.MyLongId = 1" filter does not work?

Do I really need to cast all Int32 values to Int64 before I can successfully use then in a "FindMatches" call or have I stumbled on a feature or a bug?

Otherwise thanks for a great product!

/Jakob Ventzel

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 31-Oct-2006 18:29:47   

Hi, this is because in memory equality comparison is being done with the string representations.

Here's an extract of the code being executed:


...
Comparer genericComparer = Comparer.DefaultInvariant;
            bool toReturn = false;
            string valueAsString = _value as string;
            switch( _comparisonOperator )
            {
                case ComparisonOperator.Equal:
                    if( valueAsString != null )
                    {
                        toReturn = (string.Compare( fieldValue.ToString(), valueAsString, _caseSensitiveCollation, CultureInfo.InvariantCulture ) == 0);
                    }
                    else
                    {
                        toReturn = fieldValue.Equals( _value );
                    }
                    break;
...

I guess there should be better way to handle the integers. More specifically, the genericcomparer used for other types of comparison should be fine there.

Let's see what Frans thinks.

Thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39873
Joined: 17-Aug-2003
# Posted on: 31-Oct-2006 18:50:53   

It doesn't use a string compare in this case, it only uses a string compare if the value to compare with is of type string. If it's not a string, as in this case, it will do the fieldValue.Equals() call.

As the value is an int and the field value is a long value, the Equals call fails. Check this tiny snippet:


long l=0;
int i=0;
Console.WriteLine("l==i: {0}", i.Equals(l));

output: l==i: False

Which is logical, a long isn't an int.

To compare to a long, either use CLng(1) or use the VB shortcut for int64 values, which I can't find right now, but I'm sure there is one. simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 31-Oct-2006 18:51:39   

Just tried it with the opposite situation (column regular int, value int64) -> valueasstring gets null and the fieldValue.Equals( _value ) gets false. Seems it needs some more investigations

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 31-Oct-2006 18:54:29   

ok Frans, missed your comment and your post. Now, I'd think it's not expected behaviour and a custom switch might make it a little safer.

Cheers

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39873
Joined: 17-Aug-2003
# Posted on: 31-Oct-2006 20:13:08   

Jessynoo wrote:

ok Frans, missed your comment and your post. Now, I'd think it's not expected behaviour and a custom switch might make it a little safer.

Cheers

Unfortuntaly that's not possible. The thing is: it then needs a big conversion table from each value type to every other value type.

'1' fits in a byte, short, int, int64, and 1.0 is equal to 1, so you can also argue that a single and a double which are 1.0 should be comparable with 1. The problem is that the value is a type and the field's value is also a type and if these don't match, the compare will fail. I think that passing in the value of the right type is the right way to do this, how silly it might sound. However, consider this too: if you compare a short field with 200000 you might think it's ok, but it will give an overflow, though at runtime. At compiletime, the compiler would have warned that casting 200000 to a short isn't possible.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 2
Joined: 31-Oct-2006
# Posted on: 01-Nov-2006 09:25:49   

Ok I see your points.

I was just a bit surprised when I came across this as I hadn't had any problems with the filters I use for the FetchEntity operations (which I know is because those operations end up as SQL commands in the form of strings).

I suggest that you put a notice in the documentation drawing attention to the fact that FindMatches can behave differently from FetchEntities even when using the same filters.

Thanks for the quick replys.

/Jakob

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39873
Joined: 17-Aug-2003
# Posted on: 01-Nov-2006 10:24:05   

I'll add the note to the in-memory filtering text simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 08-Nov-2006 03:44:59   

Otis wrote:

Unfortuntaly that's not possible. The thing is: it then needs a big conversion table from each value type to every other value type.

Well I wasn't thinking of being exhaustive (as you've shown it's just impossible), but just to have a few switches handling the usual comparison tricks and then a default bringing back the current code.

Otis wrote:

'1' fits in a byte, short, int, int64...

then I guess if you convert all int types to an int64 and make the comparison by value, you're safe with overflow exceptions. You could probably apply the same with float vs double.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39873
Joined: 17-Aug-2003
# Posted on: 08-Nov-2006 12:00:20   

Ok, I'll see if I can add more fine grained checks in v2.1.

Frans Bouma | Lead developer LLBLGen Pro