views:

690

answers:

4

hi guys,

i'm having some issues getting the .Filter() method to work in subsonic, and i'm constantly getting errors like the one below:

Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.    

Line 36:                     bool remove = false;
Line 37:                     System.Reflection.PropertyInfo pi = o.GetType().GetProperty(w.ColumnName);
Line 38:                     if (pi.CanRead)
Line 39:                     {
Line 40:                         object val = pi.GetValue(o, null);

i'm making calls like the one below- is this the corrent way to use it? There seems to be no documentation on the use of this method

            NavCollection objTopLevelCol = objNavigation.Where(Nav.Columns.NavHigherID,Comparison.Equals, 0).Filter();

thanks in advance

A: 

IF you're using .net 3.5 you could just do this with a lambda function:

NavCollection objTopLevelCol = 
  objNavigation.Where(nav => nav.NavHigherID == 0);
Adam
Hi Adam, While this is really simple the clients application is in 2.0
Doug
A: 

Filter is designed to work on a collection - is "objNavigation" a collection? The problem you're running into is that the criteria for Filter() can't be met with the column name "NavHigherID".

Rob Conery
that is the problem - objNavigation is a collection "NavCollection" made up of "Nav"i thought that maybe i was using it wrong - am i correct in my use of ".WHERE().Filter()" in replacement of ".WHERE().LOAD()" ??and will the filter FURTHER filter the collection or add wheres to the base whole collection and start again?thanks in advance
Doug
Oh - yes I think you hit it. Try to use Where(...).Load() to load the list first - then use Filter(). That should do it...
Rob Conery
Hi again.The following code still fails with a NullReferenceException (the last one is there just so i can see it in the debugger)NavCollection objFullCollection = new NavCollection().Load();NavCollection objTopLevel = objFullCollection.Where(Nav.Columns.NavHigherID, 0).Filter();NavCollection objFinalCol = objTopLevel;
Doug
sorry about the lack of line breaks - SOF editor removed them
Doug
A: 

I was having same prob, try doing your filter like this :

lCol = objNavigation.Where("NavHigherID",Comparison.Equals, 0).Filter();
Justin Moore
Sadly i still have exactly the same issue. i have tested even with simply loading a collection, and then loading it into another collection with where() and filter (even doing exactly the above) and the "pi" in the filter method always is null.Is everyone sure this is not a bug? has anyone tested it and if so can i have a code example of a working bit of code?
Doug
+1  A: 

The value you filter against needs to be the Property Name, not the database column name.

You might try this:

lCol = objNavigation.Where(Nav.HigherIDColumn.PropertyName,Comparison.Equals, 0).Filter();

Or here's a slightly more verbose method that works for me based on custom overrides of the .Filter() method. It seemed to work better (for me at least) by explicitly creating the Where beforehand:

    SubSonic.Where w = new SubSonic.Where();
    w.ColumnName = Nav.HigherIDColumn.PropertyName;
    w.Comparison = SubSonic.Comparison.NotIn;
    w.ParameterValue = new string[] { "validvalue1", "validvalue2" };

    lCol = objNavigation.Filter(w, false);

Here's the overrides:

    /// <summary>
 /// Filters an existing collection based on the set criteria. This is an in-memory filter.
 /// All existing wheres are retained.
    /// </summary>
    /// <returns>NavCollection</returns>
 public NavCollection Filter(SubSonic.Where w)
    {
  return Filter(w, false);
 }

    /// <summary>
 /// Filters an existing collection based on the set criteria. This is an in-memory filter.
 /// Existing wheres can be cleared if not needed.
    /// </summary>
    /// <returns>NavCollection</returns>
 public NavCollection Filter(SubSonic.Where w, bool clearWheres)
    {
  if (clearWheres)
  {
   this.wheres.Clear();
  }
  this.wheres.Add(w);
  return Filter();
 }

    /// <summary>
 /// Filters an existing collection based on the set criteria. This is an in-memory filter.
 /// Thanks to developingchris for this!
    /// </summary>
    /// <returns>NavCollection</returns>
 public NavCollection Filter()
    {
        for (int i = this.Count - 1; i > -1; i--)
        {
            Nav o = this[i];
            foreach (SubSonic.Where w in this.wheres)
            {
                bool remove = false;
                System.Reflection.PropertyInfo pi = o.GetType().GetProperty(w.ColumnName);
                if (pi != null && pi.CanRead)
                {
                    object val = pi.GetValue(o, null);
                    if (w.ParameterValue is Array)
                    {
                        Array paramValues = (Array)w.ParameterValue;
                        foreach (object arrayVal in paramValues)
                        {
                            remove = !Utility.IsMatch(w.Comparison, val, arrayVal);
                            if (remove)
                                break;
                        }
                    }
                    else
                    {
                        remove = !Utility.IsMatch(w.Comparison, val, w.ParameterValue);
                    }
                }


                if (remove)
                {
                    this.Remove(o);
                    break;
                }
            }
        }
        return this;
    }

And SubSonic 2.0 doesn't actually support In/NotIn for the IsMatch function, so here's the customized version that does (in SubSonic\Utility.cs):

 public static bool IsMatch(SubSonic.Comparison compare, object objA, object objB)
 {
  if (objA.GetType() != objB.GetType())
   return false;

  bool isIntegerVal = (typeof(int) == objA.GetType());
  bool isDateTimeVal = (typeof(DateTime) == objA.GetType());

        switch (compare)
        {
   case SubSonic.Comparison.In:
            case SubSonic.Comparison.Equals:
    if (objA.GetType() == typeof(string))
     return IsMatch((string)objA, (string)objB);
    else
     return objA.Equals(objB);
   case SubSonic.Comparison.NotIn:
   case SubSonic.Comparison.NotEquals:
    return !objA.Equals(objB);
   case SubSonic.Comparison.Like:
    return objA.ToString().Contains(objB.ToString());
   case SubSonic.Comparison.NotLike:
    return !objA.ToString().Contains(objB.ToString());
   case SubSonic.Comparison.GreaterThan:
    if (isIntegerVal)
    {
     return ((int)objA > (int)objB);
    }
    else if (isDateTimeVal)
    {
     return ((DateTime)objA > (DateTime)objB);
    }
                break;
   case SubSonic.Comparison.GreaterOrEquals:
    if (isIntegerVal)
    {
     return ((int)objA >= (int)objB);
    }
    else if (isDateTimeVal)
    {
     return ((DateTime)objA >= (DateTime)objB);
    }
    break;
   case SubSonic.Comparison.LessThan:
    if (isIntegerVal)
    {
     return ((int)objA < (int)objB);
    }
    else if (isDateTimeVal)
    {
     return ((DateTime)objA < (DateTime)objB);
    }
    break;
   case SubSonic.Comparison.LessOrEquals:
    if (isIntegerVal)
    {
     return ((int)objA <= (int)objB);
    }
    else if (isDateTimeVal)
    {
     return ((DateTime)objA <= (DateTime)objB);
    }
    break;
        }
  return false;
 }
ranomore