Nhibernate类中相同类型的多个组件属性

时间:2010-02-09 10:36:46

标签: nhibernate hibernate properties components

我有一个LINE类,它包含两个POINT类型的属性。 我希望POINT成为一个组件属性。 如果LINE只包含1个POINT,这没有问题,但由于它包含2个POINT,我认为我需要区分它们(因此前缀或后缀可以应用于列名)。 我尝试使用ComponentProperty标记的PropertyName属性,但在LINE表中仍然只生成一组X和Y列。

为清楚起见,我的目标是拥有一个带有Point1_X,Point1_Y,Point2_X和Point2_Y列的LINE表。

我使用Nhibernate.Mapping.Attributes,下面你可以看到我的映射

[Class]
public class Line : EntityBase
{
  [ComponentProperty(PropertyName = "Point1")]
  public UiPoint Point1 { get; set; }

  [ComponentProperty(PropertyName = "Point2")]
  public UiPoint Point2 { get; set; }

  //omitted the constructor

}

[Component]
public class UiPoint
{
  [Property]
  public double X { get; set; }

  [Property]
  public double Y { get; set; }

  //omitted the constructor 
}

同时我想出了以下XML映射将解决我的问题

<class name="Domain.WashProcessLine,Domain">
    <id name="Id" />
    <component name="Point1">
       <property name="X" type="Double" column="Point1_X" />
       <property name="Y" type="Double" column="Point1_Y" />
    </component>
    <component name="Point2">
        <property name="X" type="Double" column="Point2_X" />
        <property name="Y" type="Double" column="Point2_Y" />
    </component>
</class>

https://www.hibernate.org/hib_docs/nhibernate/html/components.html

上找到了一个选项

以下标记创建了所需的表结构,但在从数据库中检索属性时,确实给出了一个转换异常(从UiPoint到IDictionary)。

所以我还没完全在那里:(

[Class]
public class Line : EntityBase
{
    [DynamicComponent(1)]               
    [Property(2, Name = "X", Column = "Point1_X", TypeType = typeof(double))]
    [Property(3, Name = "Y", Column = "Point1_Y", TypeType = typeof(double))]
    public UiPoint Point1 { get; set; }

    [DataMember]
    [DynamicComponent(1)]               
    [Property(2, Name = "X", Column = "Point2_X", TypeType = typeof(double))]
    [Property(3, Name = "Y", Column = "Point2_Y",TypeType=typeof(double))]
    public UiPoint Point2 { get; set; }
}

2 个答案:

答案 0 :(得分:1)

在查看Nhibernate.Mapping.Attributes的单元测试并尝试了许多不同的解决方案之后,我们发现(不幸的是)修复上面提供的情况的最简单方法是将一些原始xml注入到我们的映射中。这意味着我们删除了行类中的属性属性,并将其替换为单个条目,如下所示

[RawXml(After=typeof(ComponentAttribute), Content = @"<component name=""Point1"">
<property name=""X"" type=""Double"" column=""Point1_X"" />
   <property name=""Y"" type=""Double"" column=""Point1_Y"" />
</component>
<component name=""Point2"">
    <property name=""X"" type=""Double"" column=""Point2_X"" />
    <property name=""Y"" type=""Double"" column=""Point2_Y"" />
</component>")]

答案 1 :(得分:0)

这个问题和答案在玩NHibernatePets Sample

时帮助了我

我以为我会考虑上面的Line / Point实现。如果有人有兴趣,我的代码如下。我发现了使用属性的一些令人沮丧的怪癖。第一种情况是,如果您使用具有[Id]声明的多个类,例如:

    [Id(Name = "id")]
    [Generator(1, Class = "native")]

然后您需要为Generator指定订单号(1),否则生成的映射可能会省略一个或多个类的Generator属性。显然这与VS处理事物的方式有关。

我在使用以下方法将示例Pet.hbm.xml文件与生成的文件输出进行比较时发现了另一件事:

//Export to a mapping file when required. Test/Production. HbmSerializer.Default.Serialize(typeof(Pet).Assembly,"Pets.hbm.xml");

是不应在[Id]属性中设置Access =“field”属性,即使它位于样本映射文件中。

Line和UiPoint类(在NHibernatePets命名空间中)......

[Class(Lazy = true)]
public class Line
{

    [Id(Name = "id")]
    [Generator(1, Class = "native")]
    #if useAttributes
        virtual public int id { get; set; }
    #else
        private int id;
    #endif

    const string point1 =
    @"<component name= ""Point1"" class= ""NHibernatePets.UiPoint"" >
        <property name=""X"" 
              type=""Double"" 
              column=""Point1_X""/> 
        <property name=""Y"" 
              type=""Double"" 
              column=""Point1_Y""/>
      </component>";

    const string point2 =
    @"<component name=""Point2"" class=""NHibernatePets.UiPoint"" >
          <property name=""X""
              type=""Double""
              column=""Point2_X""/>
          <property name=""Y""
              type=""Double""
              column=""Point2_Y""/>
      </component>";

    [RawXml(After = typeof(ComponentAttribute), Content = point1)]
    virtual public UiPoint Point1 { get; set; }

    [RawXml(After = typeof(ComponentAttribute), Content = point2)]
    virtual public UiPoint Point2 { get; set; }

}

//Don't need any Attributes set on this class as it's defined in the RawXml.
public class UiPoint
{
    public double X { get; set; }
    public double Y { get; set; }
}

在Main()......

        //Create the Line record
        Line newLine = new Line
        {
            Point1 = new UiPoint { X = 100.1, Y = 100.2 },
            Point2 = new UiPoint { X = 200.1, Y = 200.2 }
        };
        try
        {
            using (ISession session = OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Save(newLine);
                    transaction.Commit();
                }
                Console.WriteLine("Saved NewLine to the database");
            }
        }
        catch (Exception e)
        { Console.WriteLine(e); }

在公共课程中......

    static ISessionFactory SessionFactory;
    static ISession OpenSession()
    {

        if (SessionFactory == null) //not threadsafe
        { //SessionFactories are expensive, create only once
            Configuration configuration = new Configuration();

            #if useAttributes
            {
                configuration.SetDefaultAssembly("NHibernatePets");
                //configuration.SetDefaultAssembly(System.Reflection.Assembly.GetExecutingAssembly().ToString());
                //To use Components and other structures, AssemblyName must be set.
                //configuration.SetDefaultAssembly(typeof(Pet).Assembly.ToString());
                configuration.AddInputStream(NHibernate.Mapping.Attributes.HbmSerializer.Default.Serialize(typeof(Pet).Assembly));
            }
            #else
                configuration.AddAssembly(Assembly.GetCallingAssembly());
            #endif

            //Export to a mapping file when required. Test/Production.
            HbmSerializer.Default.Serialize(typeof(Pet).Assembly,"Pets.hbm.xml");

            SessionFactory = configuration.BuildSessionFactory();
        }
        return SessionFactory.OpenSession();
    }