NHibernate просит .NET преобразовать строковый параметр в целое число, не знаю почему - PullRequest
1 голос
/ 13 июля 2010

(отредактировано, чтобы не вести по неправильной дороге)

Прежде чем дать подробности, очень короткая версия: у меня есть оператор SQL, который мне нужен, чтобы выйти из NHibernate, и у меня есть операторы 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 в SQL Server Managmeent Studio (SQL 2008) с ручной заменой параметров, я получаю правильный набор результатов:

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 ]

1 голос
/ 13 июля 2010

Для начала вы сопоставляете столбцы идентификаторов дважды: как ссылку и как часть составного идентификатора.

Это неправильно, вы должны использовать свободный эквивалент <key-many-to-one/> для сопоставления членов идентификатора.

Но есть еще кое-что ... если у этого класса нет данных, зачем вообще его отображать?

Если было бы лучше иметь Набор Посоха в классе и наоборот (сопоставленный как многие ко многим).

Я предполагаю, что ваш запрос к Студентам для "Персонала".

Модель:

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))
0 голосов
/ 21 июля 2010

Просто чтобы закрыть этот вопрос - я разочаровался в том, чтобы убедить NHibernate сделать то, что я хотел.Вместо этого я решил использовать General SQL Parser и оболочку для реальных поставщиков команд и соединений.Аналогичная задача по другой причине описана в http://blog.theagileworkshop.com/2009/06/09/using-schemas-with-sqlite-for-in-memory-nhibernate-tests/.. В любом случае, это позволяет избежать всей проблемы, поскольку вынуждает меня работать на уровне SQL, что позволяет только делать то, что я хочу, без попадания NHibernate вно также позволяет перехватывать HQL и даже прямой доступ к БД.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...