我在映射Id时遇到问题。实体的结构如下:
public abstract class Entity<TEntity, TId>
where TEntity : Entity<TEntity, TId>
{
public virtual TId Id { get; protected set; }
public override bool Equals(object obj)...
...
}
public class EntityA<EntityA, long> : Entity<EntityA, long>
{
public virtual EntityB B { get; private set; }
/* ... */
}
public class EntityB<EntityA, long> : Entity<EntityB, long>
{
/* ... */
}
在我的模型中,每个EntityA必须只包含一个EntityB,并且存在的每个EntityB都是EntityA的一部分。这是一种常见的一对一关系。
现在,到映射:
public class EntityAMap : ClassMap<EntityA>
{
public EntityAMap()
{
Id(x => x.Id);
HasOne(x => x.B)
.Cascade.All();
/* ... */
}
}
public class EntityBMap : ClassMap<EntityB>
{
public EntityBMap()
{
Id(x => x.Id)
.GeneratedBy.Foreign("Id");
/* ... */
}
}
然后我创建一个EntityA,它自己创建一个EntityB。然后当我保存它
var entityA = EntityAFactory.CreateNewValidEntityA();
session.SaveOrUpdate(entityA);
NHibernate抛出异常,“无法解析属性:Id”。
然而,我的日志显示EntityA被“插入”到数据库中,通过调试,我可以看到EntityA.Id被归结为一个值(即,nhibernate在保存entityA方面做得很好,检索由DB并相应地设置entityA.Id属性。)
但是,没有创建entityB(空数据库,日志不显示任何内容)。因此,在我看来NHibernate在通过“GeneratedBy.Foreign(”Id“)”定义保存EntityB时访问此属性时遇到了问题。也许是因为属性“Id”不是EntityA的属性,而是来自EntityBase,但是我所做的对我来说是正确的。
问题出在哪里?我该如何解决?
谢谢!
编辑: 在这里,我展示了一些堆栈跟踪,如果它可能会有所帮助。 正如你所看到的,它做了Cascade,它在另一个实体上做了SaveOrUpdate。
at NHibernate.Tuple.Entity.EntityMetamodel.GetPropertyIndex(String propertyName)
at NHibernate.Tuple.Entity.AbstractEntityTuplizer.GetPropertyValue(Object entity, String propertyPath)
at NHibernate.Persister.Entity.AbstractEntityPersister.GetPropertyValue(Object obj, String propertyName, EntityMode entityMode)
at NHibernate.Id.ForeignGenerator.Generate(ISessionImplementor sessionImplementor, Object obj)
...
at NHibernate.Impl.SessionImpl.SaveOrUpdate(String entityName, Object obj)
at NHibernate.Engine.CascadingAction.SaveUpdateCascadingAction.Cascade(IEventSource session, Object child, String entityName, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeToOne(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeAssociation(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeProperty(Object child, IType type, CascadeStyle style, Object anything, Boolean isCascadeDeleteEnabled)
at NHibernate.Engine.Cascade.CascadeOn(IEntityPersister persister, Object parent, Object anything)
...
at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
at myproject...
答案 0 :(得分:4)
Foreign 函数采用类而不是属性。
首先,您需要从EntityB引用EntityA:
public class EntityB<EntityA, long> : Entity<EntityB, long>
{
// this is new!
public virtual EntityA EntityA { get; private set; }
/* ... */
}
这是EntityB的新映射文件:
public EntityBMap()
{
// first reference EntityA....
References(x => x.EntityA)
.SetAttributes(new Attributes
{
{"insert", "false"},
{"update", "false"}
});
// ... then use it in the Foreign function
Id(x => x.Id)
.GeneratedBy.Foreign("EntityA");
/* ... */
}
SetAttributes 调用避免NHibernate尝试将Id字段映射两次(因此炸毁)。