流利的Nhibernate多级参考

时间:2015-10-04 18:32:02

标签: c# fluent-nhibernate

我有一个三代的类结构,我试图使用Fluent Nhibernate进行ORM-ify。总结他们看起来像这样的课程......

public class Highest{
  public virtual Guid Id{
    get;
    set;
  }

  public virtual IList<Medium> Children{
    get;
    set;
  }
}

public class Medium{
  public virtual int Index{
    get;
    set;
  }

  public virtual Highest Parent{
    get;
    set;
  }

  public virtual IList<Lowest> Children{
    get;
    set;
  }
}

public class Lowest{
  public virtual MyEnum LowType{
    get;
    set;
  }

  public virtual Medium Parent{
    get;
    set;
  }
}

我尝试过多次尝试使用最高级别的简单ID和中级和最低级别的复合ID创建相应的地图。但是我的所有策略都没有创建一个从最低到中等的复合数据,因为(我认为)它反过来使用CompositeId从它自己到最高。

问题!   如何设计地图,以便我确信当我加载最高级别时,还将创建所有中等和低级关系,包括父/子关系。

谢谢!

1 个答案:

答案 0 :(得分:2)

您请求的映射

public class HighestMap : ClassMap<Highest>
{
    public HighestMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();

        HasMany(x => x.Children)
            .KeyColumn("parent_id");
    }
}

public class MediumMap : ClassMap<Medium>
{
    public MediumMap()
    {
        CompositeId()
            .KeyReference(x => x.Parent, "parent_id")
            .KeyProperty(x => x.Index, "indexColumn");

        HasMany(x => x.Children)
            .KeyColumns.Add("medium_id", "indexColumn")
            .Component(c =>
            {
                c.ParentReference(x => x.Parent);
                c.Map(x => x.LowType);
            });
    }
}

但是你说你想要一次性加载,那么可能值得牺牲性能的可查询性。以下代码将Medium.Children集合保存为数据库中的字符串,并且只能使用相等且不相等的session.Query<Medium>().Where(x => x.Children == myCollection);

进行查询
public class Medium
{
    public virtual Highest Parent { get; set; }

    public virtual ICollection<MyEnum> Children { get; set; }
}

public class HighestMap : ClassMap<Highest>
{
    public HighestMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();

        HasMany(x => x.Children)
            .KeyColumn("parent_id")
            .AsList(i => i.Column("indexColumn"))
            .Component(c => 
            {
                c.ParentReference(x => x.Parent);

                // remove Index property and use Highest.Children.IndexOf(medium)

                c.Map(x => x.Children).CustomType<EnumCollectionAsStringUserType<MyEnum>>();
            });
    }
}

[Serializable]
public class EnumCollectionAsStringUserType<TEnum> : IUserType
{
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var value = (string)NHibernateUtil.String.Get(rs, names[0]);

        if (string.IsNullOrEmpty(value))
            return new List<TEnum>();

        return value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(Parse).ToList();
    }

    private static TEnum Parse(string arg)
    {
        return (TEnum)Enum.Parse(typeof(TEnum), arg);
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var collection = (IEnumerable<TEnum>)value;
        NHibernateUtil.String.Set(cmd, string.Join(",", collection), index);
    }

    public Type ReturnedType { get { return typeof(ICollection<TEnum>); } }

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

    public object DeepCopy(object value)
    {
        return new List<TEnum>((IEnumerable<TEnum>)value);
    }

    bool IUserType.Equals(object x, object y)
    {
        return ((IEnumerable<TEnum>)x).SequenceEqual((IEnumerable<TEnum>)y);
    }

    int IUserType.GetHashCode(object x)
    {
        return ((IEnumerable<TEnum>)x).Aggregate(0, (a, v) => a << 8 + v.GetHashCode());
    }

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

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

    public bool IsMutable { get { return true; } }

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