问题
I am trying to use the select clause to pick out an object which matches a specified name field from a database query as follows:
objectQuery = from obj in objectList
where obj.Equals(objectName)
select obj;
In the results view of my query, I get:
base {System.SystemException} = {"Boolean Equals(System.Object)"}
Where I should be expecting something like a Car
, Make
, or Model
Would someone please explain what I am doing wrong here?
The method in question can be seen here:
// this function searches the database's table for a single object that matches the 'Name' property with 'objectName'
public static T Read<T>(string objectName) where T : IEquatable<T>
{
using (ISession session = NHibernateHelper.OpenSession())
{
IQueryable<T> objectList = session.Query<T>(); // pull (query) all the objects from the table in the database
int count = objectList.Count(); // return the number of objects in the table
// alternative: int count = makeList.Count<T>();
IQueryable<T> objectQuery = null; // create a reference for our queryable list of objects
T foundObject = default(T); // create an object reference for our found object
if (count > 0)
{
// give me all objects that have a name that matches 'objectName' and store them in 'objectQuery'
objectQuery = from obj in objectList
where obj.Equals(objectName)
select obj;
// make sure that 'objectQuery' has only one object in it
try
{
foundObject = (T)objectQuery.Single();
}
catch
{
return default(T);
}
// output some information to the console (output screen)
Console.WriteLine("Read Make: " + foundObject.ToString());
}
// pass the reference of the found object on to whoever asked for it
return foundObject;
}
}
Note that I am using the interface "IQuatable<T>
" in my method descriptor.
An example of the classes I am trying to pull from the database is:
public class Make: IEquatable<Make>
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Model> Models { get; set; }
public Make()
{
// this public no-argument constructor is required for NHibernate
}
public Make(string makeName)
{
this.Name = makeName;
}
public override string ToString()
{
return Name;
}
// Implementation of IEquatable<T> interface
public virtual bool Equals(Make make)
{
if (this.Id == make.Id)
{
return true;
}
else
{
return false;
}
}
// Implementation of IEquatable<T> interface
public virtual bool Equals(String name)
{
if (this.Name.Equals(name))
{
return true;
}
else
{
return false;
}
}
}
And the interface is described simply as:
public interface IEquatable<T>
{
bool Equals(T obj);
}
回答1:
IQueryable<T>
executes your query against the backing data store (in this case, it's SQL RDBMS). Your SQL RDBMS has no idea of IEquatable<T>
*, and cannot use its implementation: the query function must be translatable to SQL, and obj.Equals(objectName)
is not translatable.
You can convert IQueryable<T>
to IEnumerable<T>
and do the query in memory, but that would be too inefficient. You should change the signature to take a Expression<Func<TSource, bool>>
predicate, and pass the name checker to it:
public static T Read<T>(Expression<Func<T,bool>> pred) {
using (ISession session = NHibernateHelper.OpenSession()) {
return session.Query<T>().SingleOrdefault(pred);
}
}
You can now use this method as follows:
Make snake = Read<Make>(x => x.Name == "snake");
* Additionally, your
IEquatable<T>
is not used in the method that you are showing: the Equals(string)
method would qualify as an implementation of IEquatable<string>
, but it is not mentioned in the list of interfaces implemented by your Make
class.
回答2:
One of your calls to the Equal override could be throwing an exception.
For debugging purposes, try iterating rather than using Linq and you should find out which one:
foreach(object obj in objectList)
{
bool check = obj.Equals(objectName) // set a breakpoint here
}
As far as what is causing the exception, ensure that each of your object Name and Id properties have values.
来源:https://stackoverflow.com/questions/12610731/c-sharp-select-clause-returns-system-exception-instead-of-relevant-object