重用NServiceBus消息传奇数据

时间:2011-06-07 06:00:14

标签: nservicebus

有没有理由不在saga数据中重用NServiceBus消息(IMessage)?我的意思是传达这样的信息:

public class Order : IMessage
{
   public virtual List<TillOrderLine> OrderLines { get; set; }
}

public class TillOrderLine : IMessage { ... }

然后在这样的传奇和传奇数据中使用它:

public class OrderProcessingSaga : 
    Saga<OrderProcessingSagaData>, 
    IAmStartedByMessages<Order> { ... }

public class OrderProcessingSagaData : ISagaEntity
{
   public virtual Guid Id { get; set; }
   public virtual string Originator { get; set; }
   public virtual string OriginalMessageId { get; set; }

   // The message data is stored by the saga here.
   public virtual Order Order { get; set; }
}

我意识到消息是由传输层(MSMQ)存储的,而传奇数据是通过saga持久保存到DB的。它适用于我当前的用例,并且重用该类似乎更优雅,而不是为消息创建一个,而为saga存储创建另一个。

我想知道这种方法是否有任何问题?

2 个答案:

答案 0 :(得分:6)

我同意mookid8000所说的一切,但我还有一个细节需要补充。

你的传奇存储通常会有很多争用。为了保证一致性,传奇存储提供程序通常会对数据进行更新锁定,以保证来自同一传奇的另一条消息不会同时改变状态。

如果你使用的是默认的NHibernate saga persister(你的虚拟属性告诉我你是),那么NHibernate会使用一些假设来保存你的数据:

  • 您的saga数据中的复杂类型将导致遵循ComplexTypePropName_ChildPropertyName语法的数据库列(或其附近 - 在此处从内存操作)。因此,您的传奇数据仍将包含在一个表格的一行中。
  • 如果你的传奇数据中有一个列表,它显然必须创建一个新表来存储列表项。现在,您的saga数据包含在一个主行和多个详细信息行中。
    • 为了让NHibernate映射它,你的集合类型还必须有一个名为Id的Guid属性,这意味着你不能存储基元列表,而你的TillOrderLine类(公共消息的一部分)需要这个Id属性这对您服务的商业目的毫无意义。
  • 如果你的saga数据中有一个复杂的类型(Order,基本上是重用的消息),我不知道你的情况会发生什么,它本身包含一个列表(TillOrderLines)。

在任何情况下,更多表中需要更多行来分割数据所需的saga persister,使用粒度行锁锁定所涉及的行的难度就越大。有足够的争用,行锁将开始升级到页锁和表锁,然后你真的遇到了问题。

这就是为什么文档数据库真的会为saga存储发光,这就是为什么在NServiceBus 3.0中他们将RavenDB作为默认的saga persister。

在那之前,看一下我写的XML Serialization based Saga Persister,这可以为即将推出的RavenDB风格的saga persister带来一些好处。

如果你必须坚持使用NHibernate,我强烈建议你不要将你的消息与你的saga持久性解决方案紧密结合起来。我几乎保证会回来困扰你。

答案 1 :(得分:2)

如果你的异常传奇持久存在数据而没有抱怨,我想不出这种方法有什么问题 - 只要你意识到你为了两个目的重用一个类,从而引入了传奇数据之间的耦合(关于服务的私人信息)和关于字段存在,命名等的消息(本质上是公开的)

然后,如果您需要偏离消息的结构方式,则可以为所有传奇数据构建类。

PS:如果TillOrderLine的唯一目的是在IMessage内汇总,则Order不需要标记为{{1}}。