2013-03-16 61 views
0

我有兩個連接的子類從同一個表中讀取具有可區分字段的鑑別器。我已經能夠使用這樣的子查詢讀取兩個實體:NHibernate問題從具有子選擇的實體中刪除

<joined-subclass name="EntityA" 
    table="t_entity" 
    subselect="SELECT * FROM t_entity WHERE t_entity.discriminator is not null"> 
    <key column="t_uid"></key> 
    <!-- more mapping --> 
</joined-subclass> 

<joined-subclass name="EntityB" 
    table="t_entity" 
    subselect="SELECT * FROM t_entity WHERE t_entity.discriminator is null"> 
    <key column="t_uid"></key> 
    <!-- more mapping --> 
</joined-subclass> 

一切都很好,但是當我嘗試刪除兩個實體,我得到一個語法錯誤之一:

NHibernate.Exceptions.GenericADOException was unhandled 
    HResult=-2146232832 
    Message=could not delete: [EntityA#27] 
    [SQL: DELETE FROM (SELECT * 
     FROM t_entity 
     WHERE t_entity.discriminator is not null) WHERE t_uid = ?] 
Source=NHibernate 

任何有關如何通過可空字段區分同一個表中的實體的更好的想法?

這裏的堆棧跟蹤:

at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Int32 j, Object obj, SqlCommandInfo sql, ISessionImplementor session, Object[] loadedState) 
    at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Object obj, ISessionImplementor session) 
    at NHibernate.Action.EntityDeleteAction.Execute() 
    at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) 
    at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) 
    at NHibernate.Engine.ActionQueue.ExecuteActions() 
    at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) 
    at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) 
    at NHibernate.Impl.SessionImpl.Flush() 
    at NHibernate.Transaction.AdoTransaction.Commit() 
    at Nephila.Toolkit.Data.Implementations.Transaction.Commit() in C:\Projects\Git\nephilaapiTFS\Toolkit\Nephila.Toolkit.Data.Implementations\Transaction.cs:line 48 
    at Nephila.Dashboard.ServiceLayer.WidgetRegistrationService.UnregisterWidget(Widget widget) in C:\Projects\Git\nephilaapiTFS\Dashboard\Nephila.Dashboard.ServiceLayer\WidgetRegistrationService.cs:line 206 
    at Nephila.Dashboard.WidgetRegistrationConsole.Instance.UnregisterWidget(String widgetUrlName) in C:\Projects\Git\nephilaapiTFS\Nephila.Dashboard.WidgetRegistrationConsole\Program.cs:line 254 
    at Nephila.Dashboard.WidgetRegistrationConsole.Instance.Display(String[] args) in C:\Projects\Git\nephilaapiTFS\Nephila.Dashboard.WidgetRegistrationConsole\Program.cs:line 97 
    at Nephila.Dashboard.WidgetRegistrationConsole.Program.Main(String[] args) in C:\Projects\Git\nephilaapiTFS\Nephila.Dashboard.WidgetRegistrationConsole\Program.cs:line 19 
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

    InnerException: System.Data.SqlClient.SqlException 
    HResult=-2146232060 
    Message=Incorrect syntax near '('. 
    Incorrect syntax near the keyword 'WHERE'. 
    Statement(s) could not be prepared. 
    Source=.Net SqlClient Data Provider 
    ErrorCode=-2146232060 
    Class=15 
    LineNumber=1 
    Number=102 
    Procedure="" 
    Server=(local) 
    State=1 
    StackTrace: 
     at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
     at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 
     at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) 
     at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) 
     at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite) 
     at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) 
     at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite) 
     at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() 
     at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) 
     at NHibernate.Persister.Entity.AbstractEntityPersister.Delete(Object id, Object version, Int32 j, Object obj, SqlCommandInfo sql, ISessionImplementor session, Object[] loadedState) 
+0

是否存在內部異常跟蹤? – eulerfx 2013-03-16 17:18:56

回答

1

除了使用子選擇,你可以使用基於鑑繼承映射,以用於鑑別一個公式,即

<class name="BaseEntity" table="t_entity"> 
    <!-- base id and properties mapping --> 

    <discriminator formula="CASE discriminator is not null 
          WHEN true THEN 'EntityA' 
          ELSE 'EntityB' 
          END" /> 

    <subclass name="EntityA" discriminator-value="EntityA"> 
    <!-- more mapping --> 
    </subclass> 

    <subclass name="EntityB" discriminator-value="EntityB"> 
    <!-- more mapping --> 
    </subclass> 
</class> 

然後,您應該能夠刪除實體。

+0

不幸的是我不能在連接子類中使用鑑別符,但是無論如何感謝:) – abx78 2013-03-17 23:40:09

+1

你是對的,你不能對連接子類使用鑑別符。但是你可以將它與子類一起使用,並且由於兩個子類都使用同一個表,因此可以根據我的答案在基類中聲明此表。請看Ayende在[NHibernate Mapping - Inheritance](http://ayende.com/blog/3941/nhibernate-mapping-inheritance)上發佈的非常好的帖子,它解釋了差異繼承策略以及它們如何映射到數據庫表。 – mickfold 2013-03-18 08:56:15

+0

我不得不按照另一種方法,但你的答案是有道理的。謝謝! – abx78 2013-03-18 18:45:30

0

對我來說,答案是在兩個不同的表在兩個實體分割保持一個共同的基礎表中的公共字段,並設置在每個子表自己的寶貴信息。

<joined-subclass name="BaseEntity" 
    table="t_entity_base" 
    abstract="true"> 
     <key column="t_uid"></key> 
     <!-- common mapping --> 

    <joined-subclass name="EntityA" 
     table="t_entity_a"> 
     <key column="t_uid"></key> 
     <!-- specific fields, i.e.: --> 
     <property name="discriminator" column="discriminator"/> 

    </joined-subclass> 


    <joined-subclass name="EntityB" 
     table="t_entity_b"> 
     <key column="t_uid"></key> 

    </joined-subclass> 

</joined-subclass> 

感謝您的幫助。