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

发布于 2024-09-08 23:35:21 字数 7671 浏览 5 评论 0原文

(经过编辑以避免走上错误的道路)

在提供详细信息之前,非常简短的版本:我有一个需要从 NHibernate 中退出的 SQL 语句,并且我有 Criteria 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 Managmeent 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
        )
    )

尝试的参数转换来自哪里?为什么会发生这种情况?我该怎么做才能避免这个问题?

谢谢!

(Edited to avoid leading down the wrong road)

Before giving details, very short version: I have a SQL statement I need to get out of NHibernate, and I have Criteria API statements that give it to me. The NHibernate is trying to do something wrong with the statement it generates, and I'm trying to figure out why.

I have the following mappings in 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);
    }
}

A similar set of code is present for a table named ClassStudent. Both of these tables are join tables.

I have the following code that runs against domain objects:

            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));
                }
            }

When I attempt to run this code, I get the following exception back:

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)

What's annoying me right now the most is that the generated SQL is exactly what I want the SQL to look like. If I run the SQL in SQL Server Managmeent Studio (SQL 2008) with manual parameter replacement I get a correct result set:

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
        )
    )

Where is the attempted parameter conversion coming from? Why is it happening? And what can I do to avoid the issue?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

神妖 2024-09-15 23:35:21

对于初学者来说,您将映射 ID 列两次:作为参考,以及作为复合 ID 的一部分。

这是错误的,您应该使用 的流畅等效项来映射 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 进行查询比 Criteria 容易得多:

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))

For starters, you are mapping the ID columns twice: as a reference, and as part of a composite-id.

This is wrong, you should use the fluent equivalent of <key-many-to-one/> to map the id members.

But there's more... if this class doesn't have any data, why map it at all?

If would be better to have a Set of Staff in Class and vice-versa (mapped as many-to-many).

I'll assume your query is to the the Students for a "Staff".

Model:

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; }
}

Mapping is just many-to-many on those collections, so I'll leave it out.

And query is a lot easier to do with HQL than Criteria:

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))
吐个泡泡 2024-09-15 23:35:21

只是为了结束这个问题 - 我放弃了说服 NHibernate 做我想做的事。我决定改用通用 SQL 解析器以及真实命令和连接提供程序的包装器。 http://blog.theagileworkshop.com/2009/06/09/using-schemas-with-sqlite-for-in-memory-nhibernate-tests/。无论如何,这避免了整个问题,因为它迫使我在 SQL 级别工作,这不仅让我可以做我想做的事情而不会受到 NHibernate 的干扰,而且还允许拦截 HQL 甚至直接数据库访问。

Just to close this question off - I gave up on convincing NHibernate to do what I wanted. I decided instead to use General SQL Parser and a wrapper around the real command and connection providers. A similar task for a different reason is described at http://blog.theagileworkshop.com/2009/06/09/using-schemas-with-sqlite-for-in-memory-nhibernate-tests/. In any event, this avoids the whole issue because it forces me to work at the SQL level, which ot only lets me do what I want without NHibernate getting in the way but also allows HQL and even direct DB access to be intercepted.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文