Filtro secondario () nel filtro di memoria
Domanda
Sto riscontrando dei problemi nel far funzionare il metodo .Filter () in subsonico e ricevo costantemente errori come quello qui sotto:
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);
Sto effettuando chiamate come quella qui sotto- è questo il modo corretto di usarlo? Sembra che non ci sia documentazione sull'uso di questo metodo
NavCollection objTopLevelCol = objNavigation.Where(Nav.Columns.NavHigherID,Comparison.Equals, 0).Filter();
grazie in anticipo
Soluzione
Il valore filtrato deve essere il Nome proprietà, non il nome della colonna del database.
Potresti provare questo:
lCol = objNavigation.Where(Nav.HigherIDColumn.PropertyName,Comparison.Equals, 0).Filter();
Oppure ecco un metodo leggermente più dettagliato che funziona per me basato su sostituzioni personalizzate del metodo .Filter (). Sembrava funzionare meglio (almeno per me) creando esplicitamente il Where in anticipo:
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);
Ecco le sostituzioni:
/// <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;
}
E SubSonic 2.0 in realtà non supporta In / NotIn per la funzione IsMatch, quindi ecco la versione personalizzata che funziona (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;
}
Altri suggerimenti
SE stai usando .net 3.5 puoi semplicemente farlo con una funzione lambda:
NavCollection objTopLevelCol =
objNavigation.Where(nav => nav.NavHigherID == 0);
Il filtro è progettato per funzionare su una raccolta - è " objNavigation " una collezione? Il problema che stai riscontrando è che i criteri per Filter () non possono essere soddisfatti con il nome della colonna "NavHigherID".
Avevo lo stesso problema, prova a fare il filtro in questo modo:
lCol = objNavigation.Where("NavHigherID",Comparison.Equals, 0).Filter();