Nhibernate:插入新的子数据并在事务中保留父级

时间:2012-03-05 09:21:36

标签: nhibernate transactions version

我有两个课程,Trip为父母,Ticket为孩子

public class Trip : Entity
{
   public string TripNo { get; set; }
   public string IsActive { get; set; }
}

public class Ticket : Entity
{
   public Trip Trip { get; set; }
   public string TicketNo { get; set; }
}

在交易中,如何确保添加新故障单与Trip.IsActive为真且不在其他事务中修改。如果我检查一个版本的旅行,它仍然可以在其他交易上修改。如果我锁定(在选定的旅程中)它将会出现性能问题,因为一秒钟内会有数千张票。 谢谢你的所有建议。

1 个答案:

答案 0 :(得分:1)

// change class to 
public class Trip : Entity
{
   public int Version { get; private set; }

   public string TripNo { get; set; }
   public string IsActive { get; set; }
}

// configure using FluentNhibernate Mapping
// in TripMap
Version(t => t.Version);

// use like this
void AddTicket(string tripno, string ticketNo)
{
    bool interupted = false;
    do
    {
        interupted = false;
        try
        {
            using(var tx = session.BeginTransaction())
            {
                var trip = session.Query<Trip>().Where(t => t.TripNo == tripno && t.IsActive).FirstOrDefault();
                if (trip == null)
                    return;
                var ticket = new Ticket { TicketNo = ticketNo, Trip = trip };
                session.SaveOrUpdate(ticket);
                tx.Commit()
            }
        }
        catch(StaleObjectException)
        {
            // someone messed up with the Trip
            interupted = true;
        }
    } while (interupted);
}

更新:证明它下载System.Data.Sqlite.dll并使用以下代码创建一个新的控制台应用程序

var config = Fluently.Configure()
    .Database(SQLiteConfiguration.Standard.InMemory().ShowSql().FormatSql())
    .Mappings(m => m.FluentMappings
        .Add<TripMap>()
    )
    .BuildConfiguration();

var sf = config.BuildSessionFactory();

using (var session = sf.OpenSession())
using (var session2 = sf.OpenSession(session.Connection))  // use the same connection because inmemory dbs are bound to the connection, nevertheless the session act as if they have different connections
{
    new SchemaExport(config).Execute(true, true, false, session.Connection, null);

    // fill the database
    int tripId = session.Save(new Trip { No = "1" });
    session.Flush();
    session.Clear();  // Clear cache

    var user1 = session.Get<Trip>(tripId);
    var user2 = session2.Get<Trip>(tripId);

    user1.No = 2;
    user2.No = 3;

    session.Flush();
    session2.Flush(); // throws StaleObjectException here
}