Force query execution without flush/commit

后端 未结 5 1102
太阳男子
太阳男子 2021-02-09 15:59

Hi i am using the transaction-per-request (session-in-view) pattern for an asp.net web application. I have a couple of points in the application where i want to Save an NHiberna

相关标签:
5条回答
  • 2021-02-09 16:35

    Can you not use nested transactions or transaction scopes to support this?

    Essentially what you are asking is for nh to assign the id before you use it, generated ids are only assigned when changes are flushed, changes are flushed only at transaction boundaries therefore can you not create an inner transaction scope to wrap the nh related persistence forcing the flush and id generation but still allowing the outer transaction to fail and roll back all work if one of the stored procedures fail.

    How do I do nested transactions in NHibernate? has some sample code that demos an approach using scopes.

    0 讨论(0)
  • 2021-02-09 16:37

    Have you tried using NHibernate's direct SQL features? Instead of breaking out into SQLCommand which NHibernate knows nothing about you can use ISession.CreateSQLQuery("native SQL here"). If you then do this inside a transaction after your Save method NHibernate should execute all the statements in order when the Commit happens. Thus:

    using(var tx = session.BeginTransaction())
    {
        try
        {
            FooClass fc = new FooClass("value");
            nhsession.Save(fc);
    
            var nativeQuery = nhsession.CreateSQLQuery("some insert/update query that depends on fc's id");
    
            // Add parameters to nativeQuery using SetXXX methods
            nativeQuery.SetXXX(...);
    
            // Save nativeQuery
            nativeQuery.Save(); // I think...
    
            tx.Commit();
        }
        catch (...)
        {
            tx.Rollback();
        }
    }
    

    See this for another similar question regarding using the NH native query: Hibernate NHibernate - Native SQL

    0 讨论(0)
  • 2021-02-09 16:47

    maybe I don't understand but can't you do it like so...

    using(var tx = session.BeginTransaction())
    {
        session.Save(entity);
        session.Flush();
    
        //perform non NH operations with entity.id
    
        tx.Commit();
    }//uncommitted transaction would be rolled back on dispose()
    
    0 讨论(0)
  • 2021-02-09 16:53

    Sounds like you want ´dirty read´ isolation level during your transaction. This will allow you to read ´uncommited´ but ´saved´ content. I´m however not fluent enough in NHibernate to give any insight on how to do it there.

    I´m sure someone else can hook in on how to do ´dirty read´ isolation level for NH.

    0 讨论(0)
  • 2021-02-09 16:59

    I'm using Castle ActiveRecord on top of NHibernate but the princple should be the same, my DTC is disabled so I'm not positive this works, but this should be the correct direction.

    Imports Castle.ActiveRecord
    imports NHibernate.Expression
    
    <ActiveRecord> _
    Public Class Test1
        Inherits ActiveRecordBase(Of Test1)
    
        Private _id As Guid
        <PrimaryKeyAttribute(PrimaryKeyType.Guid)> _
        Public overridable Property Id as Guid
            Get
                return _id
            End Get
    
            Set(value As guid)
                _id = value
            End Set
        End Property
    
    
        Private _prop1 As String
        <[Property]> _
        Public overridable Property prop1 as String
            Get
                return _prop1
            End Get
    
            Set(value As String)
                _prop1 = value
            End Set
        End Property
    
    End Class
    
    <ActiveRecord> _
    Public Class Test2
        Inherits ActiveRecordBase(Of Test2)
    
        Private _id As Guid
        <PrimaryKey(PrimaryKeyType.Guid)> _
        Public overridable Property Id as Guid
            Get
                return _id
            End Get
    
            Set(value As guid)
                _id = value
            End Set
        End Property
    
        Private _prop1 As String
        <[Property]> _
        Public overridable Property prop1 as String
            Get
                return _prop1
            End Get
    
            Set(value As String)
                _prop1 = value
            End Set
        End Property
    
        Private _t1 As Test1
        <BelongsTo()> _
        Public overridable Property t1 as Test1
            Get
                return _t1
            End Get
    
            Set(value As test1)
                _t1 = value
            End Set
        End Property
    
    
    End Class
    

    Imports Castle.ActiveRecord
    Imports NHibernate.Expression
    Imports System.Data.SqlClient
    Imports System.Transactions
    imports System.Configuration
    
    Public Module Module1
        Public Class modMain
            Public Shared Sub Main()
                Castle.ActiveRecord.ActiveRecordStarter.Initialize()
                Using T As New System.Transactions.TransactionScope(ondispose.Rollback)
                Dim x As New Test1()
                x.prop1 = "Hello"
                x.Save
    
                using c As New SqlConnection()
                    c.ConnectionString = ConfigurationManager.ConnectionStrings("Development").ConnectionString
                    Dim cmd As SqlCommand = c.CreateCommand()
                    cmd.CommandText = "insert into test2(prop1, t1) values(@prop1, @t1)"
                    Dim p As SqlParameter = cmd.CreateParameter()
                    p.Direction = parameterdirection.Input
                    p.DbType = dbtype.Guid
                    p.ParameterName = "@prop1"
                    p.Value = "Test"
    
                    cmd.Parameters.Add(p)
                    p = cmd.CreateParameter()
                    p.Direction = parameterdirection.Input
                    p.DbType = dbtype.Guid
                    p.ParameterName = "@t1"
                    p.Value = x.Id
    
                    c.Open
                    cmd.ExecuteNonQuery
                end using
    
                t.Complete
                end using
    
            End Sub
        End Class
    End Module
    
    0 讨论(0)
提交回复
热议问题