这可能更像是一般的NOSQL基础设施问题。
通过事件采购系统,我将事件文档保存到ravendb。
在我的域模型中有多种类型的事件,下面是一个基本示例:
public abstract class Event
{
public Guid AggregateId { get; set; }
public Event(Guid aggregateId)
{
AggregateId = aggregateId;
}
}
public class NewPersonEvent : Event
{
public string Name { get; set; }
public NewPersonEvent(Guid id, string name) : Base(id)
{
Name = name;
}
}
public class NewOrderEvent : Event
{
public DateTime OrderDate { get; set; }
public double OrderCost { get; set;}
public NewOrderEvent(Guid id, DateTime date, double cost) : Base(id)
{
OrderDate = date;
OrderCost = cost;
}
}
无论事件来自哪种类型的聚合,事件都会保留为事件文档。
这是在ravendb中为所有事件使用一种Document类型的最佳方法。或者将每个聚合的文档类型分组有什么好处
而不仅仅是'事件'文件,而不是'PersonEvent'文件和' OrderEvent'文档。
这两种方法的优点和缺点是什么,特别是有任何性能问题?
答案 0 :(得分:1)
您是否将事件的默认标记名称覆盖为...
docStore.Conventions.FindTypeTagName = type => typeof(Event).IsAssignableFrom(type) ? DocumentConvention.DefaultTypeTagName(typeof(Event)) : DocumentConvention.DefaultTypeTagName(type);
然后,无论何时对Event
进行查询,它都能正常工作并检索所有事件。
session.Query<Event>()
如果是这样的话,你可以用脚射击自己,因为如果你只想要一个事件的子集并且你这样做session.Query<NewPersonEvent>()
它会检索所有事件,因为你在开始时覆盖了标签约定。
你仍然可以采用另一种方式,但它不会那么直接(例如,有一个枚举事件类型和过滤枚举)。
我会投票给NOT覆盖默认的RavenDB行为,将不同的事件类型保留为自己的文档集合,并简单地使用多映射索引。
Raven文档声明静态索引优先于动态索引,因此它不应该是性能问题。 docs:
如果您不熟悉标记约定,但可以为事件的子集创建更多索引,请创建map / reduce索引以聚合每个事件类型的计数等等。
索引将是一个多地图索引,您可以选择两种风格。
选项1
public class Events_All : AbstractMultiMapIndexCreationTask
{
public Events_All()
{
AddMap<NewPersonEvent>(newPersonEvents =>
from newPersonEvent in newPersonEvents
select new
{
Id = newPersonEvent.AggregateId
});
AddMap<NewOrderEvent>(newOrderEvents =>
from newOrderEvent in newOrderEvents
select new
{
Id = newOrderEvent.AggregateId
});
}
}
选项2(反思)
public class Events_All2 : AbstractMultiMapIndexCreationTask
{
public Events_All2()
{
AddMapForAll<Event>(events =>
from @event in events
select new
{
Id = @event.AggregateId
});
}
}
以下是使用RavenDB.Tests.Helpers
和Shouldly
NuGet包的示例测试。它使用第一个示例索引,但您可以修改它以使用第二个。
public class MultimapIndexTest : RavenTestBase
{
private readonly Random _random = new Random();
[Fact]
public void GetAll_HasBoth_Success()
{
//Arrange
const string personName = "Jimmy";
double randomCost = _random.Next();
var event1 = new NewPersonEvent(Guid.NewGuid(), personName);
var event2 = new NewOrderEvent(Guid.NewGuid(), DateTime.Now, randomCost);
using (var docStore = NewDocumentStore())
{
docStore.ExecuteIndex(new Events_All());
using (var sesion = docStore.OpenSession())
{
sesion.Store(event1);
sesion.Store(event2);
sesion.SaveChanges();
}
docStore.WaitForStaleIndexesToComplete();
//Act
var events = GetAll(docStore).ToList();
//Assert
events.ShouldNotBeEmpty();
events.Count().ShouldBe(2);
var newPersonEvent = events.FirstOrDefault(x => x is NewPersonEvent) as NewPersonEvent;
newPersonEvent.ShouldNotBe(null);
newPersonEvent.Name.ShouldBe(personName);
var newOrderEvent = events.FirstOrDefault(x => x is NewOrderEvent) as NewOrderEvent;
newOrderEvent.ShouldNotBe(null);
newOrderEvent.OrderCost.ShouldBe(randomCost);
}
}
private IEnumerable<Event> GetAll(DocumentStore docStore)
{
using (var session = docStore.OpenSession())
{
return session.Query<Event, Events_All>();
}
}
}