我有一个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; }
}
答案 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();
}