views:

1298

answers:

4

I am trying to use the "Except" method on a LINQ result set using a custom implementation if IEqualityComparer to exclude certain results based on the value of a single field from the result set.

So, in simplified form I have...

'' Get collection of published sites...
Dim List1  = (From i In db.Sites _
              Where (i.StatusID = published) _
              Select i.SiteID, _
                     i.SiteName)

'' Find those with a pending site, but exclue all those whose SiteID is in List1...
Dim insComparer = New insCompare
Dim List2 = (From i In db.Sites _
             Where (i.StatusID = pending) _
             Select i.SiteID, _
                    i.SiteName).Except(List1, insComparer)

My Comparer is as follows...

Public Class insCompare
    Implements System.Collections.Generic.IEqualityComparer(Of Object)

    Public Function Equals1(ByVal x As Object, ByVal y As Object) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of Object).Equals
        Return IIf(x.SiteID = y.SiteID, True, False)

    End Function

    Public Function GetHashCode1(ByVal x As Object) As Integer Implements System.Collections.Generic.IEqualityComparer(Of Object).GetHashCode
        Return x.SiteID.ToString.ToLower.GetHashCode()

    End Function

End Class

I get an invalid cast exception on the ".Except" line with the message "Unable to cast object of type '...insCompare' to type 'System.Collections.Generic.IEqualityComparer'"

Can anyone cast light on why this might be please.

+1  A: 

It looks like it's asking that your comparer implement the non-generic interface IEqualityComparer, whereas yours implements IEqualityComparer (Of Object), which is a different interface.

AakashM
+1  A: 

It looks like you are using a database as the back end. You can't provide a custom comparer for this, as it can't be mapped to TSQL.

Have you tried Contains? i.e. where !List1.Contains(i.SiteID)?

Marc Gravell
Can you use .Contains on an element of a collection of anonymous type?
FourOaks
+1  A: 

Your problem here is that you implement IEqualityComparer(Of Object), but your lists are List(Of AT) where AT is an anonymous type, so you can't implement IEqualityComparer(Of AT).

I think your choices are:

  1. Declare a class/struct to hold the SideID/SiteName, and select into an instance of that class, then implement IEqualityComparer(Of NewClass).
  2. Use late-bound calls (ie. option explicit off, like it appears you are doing now), and put a .Cast(Of Object)() call on both lists before calling Except.
Jonathan
Thanks Jonathan. I did think of an explicit cast to a structure early on, but didn't persue it after I fixedother errors! I guess the only problem is having to keep the structure in sync with your LINQ result data fields - no big deal though.
FourOaks
+2  A: 

Use the following code.

    from t in db.Sites
where
  !
    (from t0 in db.Sites2
    select new {
      t0.SomeID
    }).Contains(new { t.SomeID })
select t

this is based in not in condition. I think this will help you. U are doing some complex thing.

Waheed
Aha! That looks more like the SQL with which I am far more familiar. I was trying to work out how to do a "WHERE SiteID NOT IN (SELECT SiteID FROM....)". Thanks.
FourOaks
Doesn't actually answer my original qhestion, but does get me where I was trying to go :-)
FourOaks