代码之家  ›  专栏  ›  技术社区  ›  MikeBaz - MSFT

nHibernate要求.NET将字符串参数转换为整数,不知道为什么

  •  1
  • MikeBaz - MSFT  · 技术社区  · 15 年前

    (编辑以避免走错道路)

    在给出详细信息之前,非常简短的版本:我有一个SQL语句需要从nhibernate中退出,并且我有一个标准API语句提供给我。NHibernate试图对它生成的语句做些错误的事情,我正试图找出原因。

    我在Fluent NHibernate中有以下映射:

    public class StaffClass {
        public virtual int Staff_DBID { get; private set; }
        public virtual int Class_DBID { get; private set; }
    
        // Equals and GetHasCode overrides not shown
        // other code originally here removed as it was distracting from the point and didn't change anything
    }
    
    public class StaffClassMap : ClassMap<StaffClass> {
        public StaffClassMap() {
            CompositeId()
                .KeyProperty(x => x.Staff_DBID)
                .KeyProperty(x => x.Class_DBID);
        }
    }
    

    对于名为classstudent的表,也存在类似的代码集。这两个表都是联接表。

    我有以下针对域对象运行的代码:

                using (transaction = session.BeginTransaction()) {
    
                    var criteria = session.CreateCriteria(typeof(Student));
    
                    var staffClasses = DetachedCriteria.For<StaffClass>()
                        .Add(Restrictions.Eq("Staff_DBID", desiredStaffDBID))
                        .SetProjection(Projections.Property("Class_DBID"));
    
                    var studentClasses = DetachedCriteria.For<ClassStudent>()
                        .Add(Subqueries.In("Class_DBID", staffClasses))
                        .SetProjection(Projections.Property("Student_DBID"));
    
                    criteria.Add(Subqueries.In("Student_DBID", studentClasses));
    
                    var students = criteria.List<Student>();
    
                    foreach (var student in students) {
                        Console.WriteLine(string.Format("Student: {0}, {1}", student.LastName, student.FirstName));
                    }
                }
    

    尝试运行此代码时,返回以下异常:

    NHibernate.ADOException occurred
      Message=could not execute query
    [ SELECT this_.Student_DBID as Student1_7_0_, this_.DistrictStudentID as District2_7_0_, this_.LastName as LastName7_0_, this_.FirstName as FirstName7_0_, this_.MidName as MidName7_0_, this_.School_DBID as School6_7_0_ FROM [Student] this_ WHERE @p0 in (SELECT this_0_.Student_DBID as y0_ FROM [ClassStudent] this_0_ WHERE @p1 in (SELECT this_0_0_.Class_DBID as y0_ FROM [StaffClass] this_0_0_ WHERE this_0_0_.Staff_DBID = @p2)) ]
    Positional parameters:  #0>Student_DBID #1>Class_DBID #2>3664
    [SQL: SELECT this_.Student_DBID as Student1_7_0_, this_.DistrictStudentID as District2_7_0_, this_.LastName as LastName7_0_, this_.FirstName as FirstName7_0_, this_.MidName as MidName7_0_, this_.School_DBID as School6_7_0_ FROM [Student] this_ WHERE @p0 in (SELECT this_0_.Student_DBID as y0_ FROM [ClassStudent] this_0_ WHERE @p1 in (SELECT this_0_0_.Class_DBID as y0_ FROM [StaffClass] this_0_0_ WHERE this_0_0_.Staff_DBID = @p2))]
      Source=NHibernate
      SqlString=SELECT this_.Student_DBID as Student1_7_0_, this_.DistrictStudentID as District2_7_0_, this_.LastName as LastName7_0_, this_.FirstName as FirstName7_0_, this_.MidName as MidName7_0_, this_.School_DBID as School6_7_0_ FROM [Student] this_ WHERE @p0 in (SELECT this_0_.Student_DBID as y0_ FROM [ClassStudent] this_0_ WHERE @p1 in (SELECT this_0_0_.Class_DBID as y0_ FROM [StaffClass] this_0_0_ WHERE this_0_0_.Staff_DBID = @p2))
      StackTrace:
           at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
           at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
           at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
           at NHibernate.Loader.Criteria.CriteriaLoader.List(ISessionImplementor session)
           at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results)
           at NHibernate.Impl.CriteriaImpl.List(IList results)
           at NHibernate.Impl.CriteriaImpl.List[T]()
           at Test.Program.Main(String[] args) in C:\Projects\Test\Test\Program.cs:line 86
      InnerException: System.FormatException
           Message=Failed to convert parameter value from a String to a Int32.
           Source=System.Data
           StackTrace:
                at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
                at System.Data.SqlClient.SqlParameter.GetCoercedValue()
                at System.Data.SqlClient.SqlParameter.Validate(Int32 index, Boolean isCommandProc)
                at System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters)
                at System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, _SqlRPC& rpc)
                at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
                at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
                at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
                at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
                at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
                at System.Data.Common.DbCommand.System.Data.IDbCommand.ExecuteReader()
                at NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
                at NHibernate.Loader.Loader.GetResultSet(IDbCommand st, Boolean autoDiscoverTypes, Boolean callable, RowSelection selection, ISessionImplementor session)
                at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
                at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
                at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
           InnerException: System.FormatException
                Message=Input string was not in a correct format.
                Source=mscorlib
                StackTrace:
                     at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
                     at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
                     at System.String.System.IConvertible.ToInt32(IFormatProvider provider)
                     at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
                     at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
    

    最让我恼火的是,生成的SQL正是我希望SQL看起来的样子。如果我在SQL Server Management Studio(SQL 2008)中运行SQL并手动替换参数,则会得到正确的结果集:

    SELECT
        this_.Student_DBID as Student1_7_0_, 
        this_.DistrictStudentID as District2_7_0_, 
        this_.LastName as LastName7_0_, 
        this_.FirstName as FirstName7_0_, 
        this_.MidName as MidName7_0_, 
        this_.School_DBID as School6_7_0_ 
    FROM
        [Student] this_ 
    WHERE 
        Student_DBID in (
            SELECT 
                this_0_.Student_DBID as y0_ 
            FROM
                [ClassStudent] this_0_ 
            WHERE Class_DBID in (
                SELECT
                    this_0_0_.Class_DBID as y0_ 
                FROM
                    [StaffClass] this_0_0_ 
                WHERE
                    this_0_0_.Staff_DBID = 3664
            )
        )
    

    尝试的参数转换来自何处?为什么会这样?我该怎么做才能避免这个问题?

    谢谢!

    2 回复  |  直到 15 年前
        1
  •  1
  •   Diego Mijelshon    15 年前

    对于初学者,您要映射两次ID列:作为引用,作为复合ID的一部分。

    这是错误的,你应该使用相当于 <key-many-to-one/> 映射ID成员。

    但还有更多…如果这个类没有任何数据,为什么要映射它呢?

    如果在课堂上有一组员工更好,反之亦然(多对多映射)。

    我假设你的问题是向学生要一个“工作人员”。

    模型:

    public class Student : Entity<Guid>
    {
    }
    
    public class Staff : Entity<Guid>
    {
    }
    
    public class Class : Entity<Guid>
    {
        public virtual ICollection<Student> Students { get; set; }
        public virtual ICollection<Staff> Staff { get; set; }
    }
    

    在这些集合中,映射是多对多的,所以我不考虑它。

    与标准相比,使用HQL进行查询要容易得多:

    var students = session.CreateQuery("see the query below")
                          .SetParameter("staff", id)
                          .List<Student>();
    
    from Student s
    where s in
            (select elements(c.Students)
             from Class c
             where :staff in elements(c.Staff))
    
        2
  •  0
  •   MikeBaz - MSFT    15 年前

    为了结束这个问题,我放弃了说服NHibernate做我想做的。我决定改用常规的SQL解析器和一个包装器来包装实际的命令和连接提供程序。基于不同原因的类似任务在 http://blog.theagileworkshop.com/2009/06/09/using-schemas-with-sqlite-for-in-memory-nhibernate-tests/ . 在任何情况下,这都避免了整个问题,因为它迫使我在SQL级别工作,这不仅让我做我想做的事情,而不妨碍nhibernate,而且还允许hql甚至直接db访问被拦截。