这是我的order和orderItem类:
public class Order : AggregateRootBase<OrderId>
{
public string CustomerName { get; private set; }
public IList<OrderItem> Items { get; set; }
public DateTime RegisterDatetime { get; private set; }
}
public class OrderItem : ValueObjectBase
{
public long Id { get; private set; }
public long OrderId { get; set; }
public long Number { get; private set; }
public long Goods { get; private set; }
public double UnitPrice { get; private set; }
}
我使用nhibernate作为我的orm。在映射此代码时,我希望订单位于Orders表和orderItem中,以存储在称为OrderItems的差异表中。 这是我的映射:
public class OrderMapping : ClassMapping<Order>
{
public OrderMapping()
{
Table("Orders");
Lazy(false);
ComponentAsId(a => a.EntityId, a => { a.Property(x => x.DbId, x => x.Column("Id")); });
Property(a=>a.CustomerName);
Property(a => a.RegisterDatetime);
Bag(a => a.Items,
mapper => {
mapper.Inverse(true);
mapper.Cascade(Cascade.None);
mapper.Table("OrderItems");
mapper.Key(k => k.Column(columnMapper => columnMapper.Name("OrderId")));
},
relation => { relation.OneToMany(); });
}
}
public class OrderItemMapping : ClassMapping<OrderItem>
{
public OrderItemMapping()
{
Lazy(false);
Id(a => a.Id);
Table("OrderItems");
Property(a => a.OrderId);
Property(a => a.Number);
Property(a => a.Goods);
Property(a => a.UnitPrice);
}
}
我也在数据库中创建了表,但是当我插入带有3 orderItems的order时,它会插入order但不会插入orderitems 谢谢您的帮助
答案 0 :(得分:1)
您已将Order
mapper.Inverse(true);
的父Items
映射为bag
,这告诉NHibernate您不希望父映射此关系。
由于子级OrderItem
没有到父级的映射,因此没有任何关系可以保存该关系。编写集合映射时,至少一侧必须为inverse(false)
。
您还设置了mapper.Cascade(Cascade.None);
,它告诉NHibernate当Order
在Items
中更改时,您不希望父Session
处理Save()
上的任何操作。
因此,除非您在每个Item
上显式调用class
,否则它们将永远不会保存。
NHibernate在自由OrderItem
布局和最佳数据库性能之间进行权衡(尽管在这种情况下很小)。
如果您确实不希望Order
拥有一个链接回其父级的Order
属性,那么只要父级OrderItem
为{ OrderItems
的更改,如果inverse(false)
的创建少于您对其执行的操作的〜10%,则在实践中此成本可以忽略不计。
在这种情况下,您可以将OrderMapping
上的Items
设置为OrderItem
。
但是我的选择是给Order
一个OrderItemMapping
字段或属性(您可以使用NHibernate映射一个私有字段!),然后将inverse(false)
的映射返回给父对象与OrderItem
一起使用,这样在保存孩子时,他们将处理该关系。保存之前,您必须确保每个Order
都填写了OrderId
字段/属性!
您也许可以通过使用Order
属性而不是对mapper.Cascade(Cascade.None);
的完整引用来实现此目的,但是您必须对此进行查找。
关于将它们保存到数据库,最简单的方法是将mapper.Cascade(Cascade.AllDeleteOrphan);
更改为Order
(可能不是确切的类名)。这样可以确保无论何时在Save()
上修改该集合,然后在Update()
上Order
/ OrderItem
上修改{{1}中的所有Items
}集合将相应地在数据库中更新。
您还可以检出不太严格的Cascade
或按照当前设置的要求手动保存。
最后检查Nhibernate文档中的bag
与set
,我怀疑您想在这里使用set
,我只会在bag
中使用inverse(true)
。如果您使用inverse(false)
bag
,则性能会受到影响,除非可以识别这些项目(您的OrderItem
具有Id
,所以可以!),但是如果可以识别项目,然后为什么不将其设置为set
!
您拥有inverse(false)
bag
带有可识别项目的唯一原因是,如果这些标识符与数据库中的主键不相关,那么这种情况就不会经常出现(或者就我而言!)。
答案 1 :(得分:1)
谢谢@ starlight54,但是我的问题像这样解决了。 我不得不像这样改变我的班级:
public class Order : AggregateRootBase<OrderId>
{
private readonly IList<OrderItem> _items;
public string CustomerName { get; private set; }
public DateTime RegisterDatetime { get; private set; }
public IReadOnlyCollection<OrderItem> Items => new ReadOnlyCollection<OrderItem>(_items);
}
public class OrderItem : ValueObjectBase
{
private readonly long _number;
private readonly long _goods;
private readonly double _unitPrice;
public long Number => _number;
public long Goods => _goods;
public double UnitPrice => _unitPrice;
}
请注意,在订购商品时,您必须创建_number,_goods和...之类的字段。 这是订单的映射:
public class OrderMapping : ClassMapping<Order>
{
public OrderMapping()
{
Table("Orders");
Lazy(false);
ComponentAsId(a => a.EntityId, a => { a.Property(x => x.DbId, x => x.Column("Id")); });
Property(a => a.CustomerName);
Property(a => a.RegisterDatetime);
IdBag(a => a.Items, map => {
map.Access(Accessor.Field);
map.Table("OrderItems");
map.Key(a => a.Column("OrderId"));
map.Id(a => {
a.Column("Id");
a.Generator(Generators.Identity);
});
}, relation => relation.Component(map => {
map.Access(Accessor.Field);
map.Property(a => a.Number, a => a.Access(Accessor.Field));
map.Property(a => a.Goods, a => a.Access(Accessor.Field));
map.Property(a => a.UnitPrice, a => a.Access(Accessor.Field));
}));
}
}
在nhibernate中,有IdBag可以帮助我准确地完成所需的工作。请注意,无需为orderItem类创建类映射。 nhibernate会自动将其插入。 但是您必须手动创建数据库。 希望对您有帮助。