NHibernate - 获取引用的列值

时间:2012-09-10 10:19:04

标签: c# nhibernate

我有这个NHibernate模型:

public class RootTable
{
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }
    public virtual DateTime? Start { get; set; }
    public virtual DateTime? Finish { get; set; }
    public virtual IList<Leaf1> ChildCollection1 { get; set; }
}

public class Leaf1
{
    public virtual int ID { get; set; }
    public virtual string Info1 { get; set; }
    public virtual string Info2 { get; set; }
    public virtual RootTable Parent { get; set; }
}

public class RootMapping : ClassMap<RootTable>
{
    public RootMapping()
    {
        Table("RootTable");
        Id(c => c.Name);
        Map(c => c.Description, "Desc").Length(20);
        Map(c => c.Start).Length(20);
        Map(c => c.Finish).Length(20);
        HasMany(c => c.ChildCollection1)
            .Cascade.All()
            .LazyLoad()
            .Inverse();
    }
}

public class Leaf1Mapping : ClassMap<Leaf1>
{
    public Leaf1Mapping()
    {
        Table("LeafTable1");
        Id(c => c.ID, "RowID").GeneratedBy.Identity();
        Map(c => c.Info1).Length(20);
        Map(c => c.Info2).Length(20);
        References(c => c.Parent).Column("Parent").LazyLoad();
    }
}

我要做的是访问Leaf1中引用列的而不延迟加载RootTable。

换句话说,我有这个:

this.LogMessage("Loading leaves...");
var allleafs = session.CreateCriteria(typeof(Leaf1)).List<Leaf1>();
this.LogMessage("Loaded leaves...");
var leaf = allleafs[0];

this.LogMessage("Leaf metadata:");
// This causes a lazy-load of the RootTable object.
this.LogMessage("Leaf parent is " + leaf.Parent);

现在我真正想要的是“父”的,因为它存储在底层数据库中 - 我不关心父对象,我不想加载它,所有我想获得原始价值。我无法访问包含该值的字段(即leaf.Parent.Name),因为我希望它以通用方式工作...

[背景] 最终,这是插入使用NHibernate拦截器的审计框架,因此需要以通用方式工作,以便对于传入的任何对象,我可以报告更改的值。子节点完全有可能在没有更改根节点的情况下进行更改,因此当调用拦截器OnFlushDirty()时,我希望拦截器导致其他延迟负载对象。

我知道我可以直接引用父属性(例如,我可以说“leaf.Parent.Name”),这将获得没有延迟加载的值,但似乎没有快速的方法确定“Name”是我想要返回的关键属性。

[已编辑添加...]
在树上行走似乎不起作用,因为我得到一个空引用异常:

var theType = leaf.Parent.GetType();

// This line returns a NULL due to the proxy class.
var metadata = factory.GetClassMetadata(theType);
var idProp = metadata.IdentifierPropertyName;

var prop = theType.GetProperty(idProp);
var val = prop.GetValue(leaf.Parent, null);

this.LogMessage("Leaf parent is " + val);

现在,theType返回为RootTableProxy,因此只是一个占位符,因为未加载主类。这意味着metadata为null,因为没有类元数据,因此idProp失败并带有空引用异常。

所以我实际上看不到如何在没有延迟加载的情况下获取引用的列值:肯定这不是正确的?

编辑添加(更多!)
我认为通过使用session.GetIdentifier()找到了一个简单的解决方案。然而,这似乎并不适用于所有情况:在一些对象上调用session.GetIdentifier(state[i])导致异常声明该对象不是当前会话的一部分,所以仍然在寻找一个更可靠的解决方案不要反思。任何想法都欢迎......

3 个答案:

答案 0 :(得分:1)

如何向Leaf1 Class添加另一个属性。

e.g。

public class Leaf1
{
    public virtual int ID { get; set; }
    public virtual string Info1 { get; set; }
    public virtual string Info2 { get; set; }
    public virtual RootTable Parent { get; set; }
    public virtual int ParentId { get; set; }
}

然后map就像readonly

public class Leaf1Mapping : ClassMap<Leaf1>
{
    public Leaf1Mapping()
    {
        Table("LeafTable1");
        Id(c => c.ID, "RowID").GeneratedBy.Identity();
        Map(c => c.Info1).Length(20);
        Map(c => c.Info2).Length(20);
        References(c => c.Parent).Column("Parent").LazyLoad();
        Map(c => c.ParentId).Column("Parent").ReadOnly();
    }
}

答案 1 :(得分:0)

你可以让你的实体实现接口(会更干净),但如果你想获得代理的实际类型,请使用NHibernateUtil.GetClass(代理),它将返回你正在寻找的基础类型

答案 2 :(得分:0)

发现ISession有一个方法GetIdentifier,它返回属性的缓存值。以我原来的帖子为例,代码改为:

this.LogMessage("Loading leaves...");
var allleafs = session.CreateCriteria(typeof(Leaf1)).List<Leaf1>();
this.LogMessage("Loaded leaves...");
var leaf = allleafs[0];

this.LogMessage("Leaf metadata:");
this.LogMessage("Leaf parent is " + session.GetIdentifier(leaf.Parent));

现在在测试中,这似乎工作得很好,并且可以在currentState和previousState对象上的拦截器中从OnFlushDirty调用。

我一直在努力寻找有关GetIdentifier的更多信息,但遗憾的是NH文档缺乏,而且似乎很少有博客文章提到这一点。如果有人知道我需要知道的关于这种方法的任何警告,问题或“有趣”,我会非常高兴听到他们...

[已编辑添加] ...事实证明,如果对象不是代理对象(!),这将不起作用。仍然在寻找一种可靠的方法,不需要反射或装饰具有属性的对象来识别字段。