在具有不同列名的不同表上使用 ICompositeUserType

发布于 2024-08-23 15:27:24 字数 1705 浏览 2 评论 0原文

我一直在尝试让 NHibernate ICompositeUserType 映射发挥作用。但我一直试图使实现足够通用以在不同的表上使用。

我们的遗留数据库有许多带有纬度和经度的表,我想将它们作为 Position 类映射到我的域对象中。问题是每个表的纬度和经度列都有不同的名称。

我已经创建了 ICompositeUserType 的实现,但我似乎必须将 PropertyNames 设置为表中的列名称,这意味着我无法在不同的表(具有不同的列名称)上使用 CustomType。

我认为我应该将 PropertyNames 设置为 Position 类中的属性名称,并将它们映射到 ClassMap 中的表列,但这似乎会引发 NHibernate 异常

NHibernate.MappingException: property mapping has wrong number of columns

:映射,但我无法弄清楚。

的代码片段,

public class PositionUserType : ICompositeUserType
{
  private readonly IType[] _propertyTypes = 
     new [] { NHibernateUtil.Double , NHibernateUtil.Double };

  private readonly string[] _propertyNames = 
     new[] { "Latitude", "Longitude"  };

  public string[] PropertyNames { get { return _propertyNames; } }

  public IType[] PropertyTypes { get { return _propertyTypes; } }

  // Other methods omitted
}

这是来自我的 ICompositeUserType:和我的 Class Map:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)
            .Columns.Add("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

以及 Position 类

public class Position
{
  public double Latitude { get; private set; }
  public double Longitude { get; private set; }

  public Position(double latitude, double longitude)
  {
    Latitude = latitude;
    Longitude = longitude;
  }
}

我目前已经解决了可以使用组件流畅映射的问题,但这意味着我的 Position 类必须是可变的,我更喜欢如果不是的话。

有人可以帮忙吗?我已经仔细阅读了几篇文章和书籍,但似乎仍然无法使其发挥作用。

谢谢,

亚当

I've been trying to get an NHibernate ICompositeUserType mapping to work. But am stuck trying to make the implementation generic enough to use on different tables.

Our legacy database has many tables with latitudes and longitudes in and I want to map them into my domain objects as a Position class. The problem is each table has different names for the latitude and longitude columns.

I've created an implementation of the ICompositeUserType but I seem to have to set the PropertyNames to the names of the columns in a table, which means I can't use the CustomType on different tables (with different column names).

I thought I should set the PropertyNames to the names of the properties in my Position class, and map them to the table columns in my ClassMap, but this seems to throw a NHibernate exception of:

NHibernate.MappingException: property mapping has wrong number of columns

It feels like I'm doinging something wrong in my mapping, but I can't figure it out.

Here is a snippet of code from my ICompositeUserType:

public class PositionUserType : ICompositeUserType
{
  private readonly IType[] _propertyTypes = 
     new [] { NHibernateUtil.Double , NHibernateUtil.Double };

  private readonly string[] _propertyNames = 
     new[] { "Latitude", "Longitude"  };

  public string[] PropertyNames { get { return _propertyNames; } }

  public IType[] PropertyTypes { get { return _propertyTypes; } }

  // Other methods omitted
}

and my Class Map:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)
            .Columns.Add("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

and the Position class

public class Position
{
  public double Latitude { get; private set; }
  public double Longitude { get; private set; }

  public Position(double latitude, double longitude)
  {
    Latitude = latitude;
    Longitude = longitude;
  }
}

I've currently got a work around where I can use a Component fluent map, but this means my Position class must be mutable, and I would prefer it if it wasn't.

Can anyone help? I've had a good look at several articles and books but I still can't seem to get it to work.

Thanks,

Adam

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独孤求败 2024-08-30 15:27:24

在映射中添加列名称覆盖之前,您需要清除列集合:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)

            // Clear the columns to get rid of Fluent NH's default column names
            .Columns.Clear()

            .ColumnsAdd("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

如果在添加自定义名称之前未清除列集合,Fluent NH 只需将新列名称附加到用户类型映射的列集合中,这会导致您为给定的用户类型获得太多列。

如果您从流畅的映射中生成实际的 XML 映射(通过在流畅的配置中使用 Mappings.ExportTo() ),您可能会看到类似这样的内容:

<property <!-- details here -->
  <column name="Latitude" /> 
  <column name="Longitude" /> 
  <column name="LPLongitude" /> 
  <column name="LPLatitude" /> 
</property>

实际上应该是:

<property <!-- details here -->
  <column name="LPLatitude" /> 
  <column name="LPLongitude" /> 
</property>

You need to clear the Column collection before adding the column name overrides in your mapping:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)

            // Clear the columns to get rid of Fluent NH's default column names
            .Columns.Clear()

            .ColumnsAdd("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

If you don't clear the column collection before adding the custom names, Fluent NH simply appends the new column names to the column collection for the user type mapping, which leads to that you get too many columns for the given user type.

If you generate the actual XML-mappings from your fluent mappings (by using Mappings.ExportTo() in your fluent configuration) you would probably see something like this:

<property <!-- details here -->
  <column name="Latitude" /> 
  <column name="Longitude" /> 
  <column name="LPLongitude" /> 
  <column name="LPLatitude" /> 
</property>

when it should actually be:

<property <!-- details here -->
  <column name="LPLatitude" /> 
  <column name="LPLongitude" /> 
</property>
一页 2024-08-30 15:27:24

它不必是可变的,您可以使用私有 backingfield

Component(x => x.Position, c =>
    {
        c.Map(p => p.Longitude, "LPLongitude").Access.BackingField();
        c.Map(p => p.Latitude, "LPLatitude").Access.BackingField();
    })

唯一需要的是该类的无参数构造函数,用户代码看不到

protected Position() { } // to make NHibernate default implementation happy

另一种可能性是使用实例化挂钩并使用 default 实例化 Position 类(double) 在构造函数中

It doesn't have to be mutable, you can use the private backingfield

Component(x => x.Position, c =>
    {
        c.Map(p => p.Longitude, "LPLongitude").Access.BackingField();
        c.Map(p => p.Latitude, "LPLatitude").Access.BackingField();
    })

the only thing needed is a parameterless constructor to the class which usercode doesn't see

protected Position() { } // to make NHibernate default implementation happy

another possibility is to use the instantiation hook and instantiate the Position class with default(double) in the constructor

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文