如何从数据库加载实体,其中记录的复合ID包含具有空值的键属性?

时间:2011-07-18 12:39:38

标签: oracle nhibernate

我正在通过Oracle10g提供程序使用Oracle.DataAccess从外部组织读取数据。其中一个表具有由这些字段组成的复合ID。

course:
  institutioncode: "X11"
  coursecode:      "N100"
  campuscode:      "A"
  entryyear:       2011
  entrymonth:      10

问题是外部提供商允许校园代码为空,而不是空。这导致nHibernate返回包含空引用而不是课程实体的集合。

其他域对象也将使用这些字段来引用此课程实体,因此这实际上用作键,我不能轻易地重新映射以使用代理键。

从标记3.1.0GA中的来源,可以在Nhibernate.Type.ComponentType.Hydrate(IDataReader rs, string[] names, ISessionImplementor session, object owner)中找到导致此行为的检查。这总是拒绝key-property可能为null的可能性。这可以改为使可空性成为关键属性和键引用属性的一个选项吗?

如果不这样做,你会如何建议直接用nHibernate读取这些数据?

2 个答案:

答案 0 :(得分:2)

属性中的NULL值不受设计支持

有两种方法可以解决这个问题:

  • 导入数据,而不是从源中使用原始数据,添加适当的代理键。
  • 处理没有NHibernate的实体。

答案 1 :(得分:1)

好的,我的第一条评论在参考文献(ManyToOne)上没有成功。所以这里是我的替代解决方案:使用usertype来解决检查问题。

class CourseMap : ClassMap<Course>
{
    public CourseMap()
    {
        CompositeId()
            .KeyProperty(c => c.InstitutionCode)
            .KeyProperty(c => c.CourseCode)
            .KeyProperty(c => c.CampusCode, key => key.Type(typeof(MyUserType)))
            .KeyProperty(c => c.EntryYear)
            .KeyProperty(c => c.EntryMonth);
    }
}

class MyUserType : IUserType
{
    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public new bool Equals(object x, object y)
    {
        return object.Equals(x, y);
    }

    public int GetHashCode(object x)
    {
        return (x == null) ? 0 : x.GetHashCode();
    }

    public bool IsMutable
    {
        get { return false; }
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var value = NHibernateUtil.String.NullSafeGet(rs, names[0]);
        return (value == null) ? string.Empty : value;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        string d = string.IsNullOrEmpty((string)value) ? null : (string)value;
        NHibernateUtil.String.NullSafeSet(cmd, d, index);
    }

    public object Replace(object original, object target, object owner)
    {
        return DeepCopy(original);
    }

    public Type ReturnedType
    {
        get { return typeof(string); }
    }

    public SqlType[] SqlTypes
    {
        get { return new[] { SqlTypeFactory.GetString(100) }; }
    }
}



class SomeEntityMap : ClassMap<SomeEntity>
{
    public EntityMap()
    {
        Id(e => e.Id).GeneratedBy.Assigned();

        References(e => e.Course)
            .Columns("InstitutionCode", "CourseCode", "CampusCode", "EntryYear", "EntryMonth")
            .Fetch.Join();  // important because we can't rely on values, NULL is invalid value
    }
}