2

I have a saga that has 3 states -

    public static State Initial { get; set; }
    public static State ReceivingRows { get; set; }
    public static State Completed { get; set; }

It transitions from Initial to ReceivingRows when it gets a BofMessage (where Bof = Beginning of file). After the BofMessage, it receives a large number of RowMessages where each describes a row in a flat file. Once all RowMessages are sent, an EofMessage is sent and the state changes to Completed. Observe -

static void DefineSagaBehavior()
{
    Initially(When(ReceivedBof)
        .Then((saga, message) => saga.BeginFile(message))
        .TransitionTo(ReceivingRows));

    During(ReceivingRows, When(ReceivedRow)
        .Then((saga, message) => saga.AddRow(message)));

    During(ReceivingRows, When(ReceivedRowError)
        .Then((saga, message) => saga.RowError(message)));

    During(ReceivingRows, When(ReceivedEof)
        .Then((saga, message) => saga.EndFile(message))
        .TransitionTo(Completed));
}

public override void OnAddRow(ParcelRowMessage message)
{
    // ensure isCauvReturned is "Y"
    var fields = message.Value;
    var isCauvReturned = fields[33] == "Y";
    if (!isCauvReturned)
        return;

    // add row with just parcel number
    var parcelNumber = fields[1];
    var row = parcelNumber;
    _rows.Add(row);
}

This works except that it has n-squared performance. Investigating with NHProf reveals that each row add causes the entire list of rows to be:

A) selected from the database

B) deleted from the database

C) reinserted into the database.

This seems like very bad behavior to me. All that is needed to add a row is to… well, add a single row to the database! The add operation is literally the only thing I’m doing with the row list. This does not scale when we have 10,000's of items in the list.

Does anyone know how to give this saga more sane performance behavior?

BTW - here's how the IList is mapped if you need it -

        HasMany(x => x.Rows)
            .Table("OwnerHistorySagaRow")
            .KeyColumn("CorrelationId")
            .Element("Row")
            .Cascade.AllDeleteOrphan();

Thank you!

Bryan Edds
  • 1,696
  • 12
  • 28

2 Answers2

3

I know this is a dead item, but here's the real answer for getting a bag to work properly.

Bag(x => x.Rows, c =>
{
    c.Key(k =>
    {
        k.Column("RowCorrelationId");
        k.ForeignKey("FK_State_Row");
        k.NotNullable(true);
    });
    c.Fetch(CollectionFetchMode.Join);
    c.Lazy(CollectionLazy.NoLazy);
    c.Cascade(Cascade.All);
}, r => r.OneToMany());

The class type for Rows is IList<Row>.

Chris Patterson
  • 28,659
  • 3
  • 47
  • 59
1

Please have a look at

https://community.jboss.org/wiki/NHibernateUsersFAQ#NHibernate_is_deleting_my_entire_collection_and_recreating_it_instead_of_updating_the_table

bearrito
  • 2,217
  • 1
  • 25
  • 36
  • 1
    I researched this, but I am afraid it doesn't give me enough specifics to go on. Could you give a more specific answer? – Bryan Edds May 23 '12 at 12:43