如何自动映射 List或者使用 Fluent NHibernate 进行 float[] ?

发布于 2024-08-10 19:25:04 字数 3143 浏览 5 评论 0原文

成功运行示例程序后,我现在开始 使用 Fluent NHibernate 进行实际工作 - 尝试在我的项目类上使用 Automapping 继承制。

这是一个科学仪器应用程序,我正在上课 映射有几个浮点数组属性,例如

    private float[] _rawY; 
    public virtual float[] RawY 
    { 
        get 
        { 
            return _rawY; 
        } 
        set 
        { 
            _rawY = value; 
        } 
    } 

这些数组最多可以包含 500 个值。

我没想到自动映射可以在数组上工作,但还是尝试了一下, 起初取得了一些成功。每个数组都自动映射到 BLOB (使用 SQLite),这似乎是一个可行的解决方案。

当我尝试调用 SaveOrUpdate 时出现了第一个问题 包含数组的对象 - 我得到“No persister for float[]” 例外情况。

所以我的下一个想法是将所有数组转换为 IList,例如

public virtual IList<float> RawY { get; set; } 

但现在我得到:

NHibernate.MappingException: Association references unmapped class: System.Single 

由于 Automapping 可以处理复杂对象的列表,所以它永远不会 我发现它无法映射基本类型的列表。但 在谷歌搜索了一些解决方案后,情况似乎就是这样。 有些人似乎已经解决了问题,但是我的示例代码 saw 需要比我现在更多的 NHibernate 知识 - 我 不明白。

问题:

1。我如何才能使用 Automapping 来实现此功能?

2.另外,对于此应用程序,使用数组或列表更好吗?

如果需要,我可以修改我的应用程序以使用其中之一(尽管我更喜欢 列表)。

编辑:

我研究了映射字符串集合中的代码,我看到源代码中有一个测试代码,用于设置字符串的 IList,例如,

public virtual IList<string> ListOfSimpleChildren { get; set; }

[Test] 
public void CanSetAsElement() 
{ 
    new MappingTester<OneToManyTarget>() 
        .ForMapping(m => m.HasMany(x => x.ListOfSimpleChildren).Element("columnName")) 
        .Element("class/bag/element").Exists(); 
} 

因此这必须可以使用纯自动映射来实现,但我在任何工作上的运气为零,可能是因为我不这样做不具备使用 NHibernate 手动映射的必要知识。

开始认为我将不得不破解这个(通过将浮点数数组编码为单个字符串,或者创建一个包含单个浮点数的类,然后将其聚合到我的列表中),除非有人可以告诉我该怎么做正确地。

结束编辑

这是我的 CreateSessionFactory 方法,如果这有助于制定一个 回复...

    private static ISessionFactory CreateSessionFactory() 
    { 
        ISessionFactory sessionFactory = null; 


        const string autoMapExportDir = "AutoMapExport"; 
        if( !Directory.Exists(autoMapExportDir) ) 
            Directory.CreateDirectory(autoMapExportDir); 


        try 
        { 
            var autoPersistenceModel = 
                AutoMap.AssemblyOf<DlsAppOverlordExportRunData>() 
                       .Where(t => t.Namespace == "DlsAppAutomapped") 
                       .Conventions.Add( DefaultCascade.All() ) 
                ; 


            sessionFactory = Fluently.Configure() 
                .Database(SQLiteConfiguration.Standard 
                              .UsingFile(DbFile) 
                              .ShowSql() 
                         ) 
                .Mappings(m => m.AutoMappings.Add(autoPersistenceModel) 
                                             .ExportTo(autoMapExportDir) 
                         ) 
                .ExposeConfiguration(BuildSchema) 
                .BuildSessionFactory() 
                ; 
        } 
        catch (Exception e) 
        { 
            Debug.WriteLine(e); 
        } 


        return sessionFactory; 
    } 

Having successfully gotten a sample program working, I'm now starting
to do Real Work with Fluent NHibernate - trying to use Automapping on my project's class
heirarchy.

It's a scientific instrumentation application, and the classes I'm
mapping have several properties that are arrays of floats e.g.

    private float[] _rawY; 
    public virtual float[] RawY 
    { 
        get 
        { 
            return _rawY; 
        } 
        set 
        { 
            _rawY = value; 
        } 
    } 

These arrays can contain a maximum of 500 values.

I didn't expect Automapping to work on arrays, but tried it anyway,
with some success at first. Each array was auto mapped to a BLOB
(using SQLite), which seemed like a viable solution.

The first problem came when I tried to call SaveOrUpdate on the
objects containing the arrays - I got "No persister for float[]"
exceptions.

So my next thought was to convert all my arrays into ILists e.g.

public virtual IList<float> RawY { get; set; } 

But now I get:

NHibernate.MappingException: Association references unmapped class: System.Single 

Since Automapping can deal with lists of complex objects, it never
occured to me it would not be able to map lists of basic types. But
after doing some Googling for a solution, this seems to be the case.
Some people seem to have solved the problem, but the sample code I
saw requires more knowledge of NHibernate than I have right now - I
didn't understand it.

Questions:

1. How can I make this work with Automapping?

2. Also, is it better to use arrays or lists for this application?

I can modify my app to use either if necessary (though I prefer
lists).

Edit:

I've studied the code in Mapping Collection of Strings, and I see there is test code in the source that sets up an IList of strings, e.g.

public virtual IList<string> ListOfSimpleChildren { get; set; }

[Test] 
public void CanSetAsElement() 
{ 
    new MappingTester<OneToManyTarget>() 
        .ForMapping(m => m.HasMany(x => x.ListOfSimpleChildren).Element("columnName")) 
        .Element("class/bag/element").Exists(); 
} 

so this must be possible using pure Automapping, but I've had zero luck getting anything to work, probably because I don't have the requisite knowlege of manually mapping with NHibernate.

Starting to think I'm going to have to hack this (by encoding the array of floats as a single string, or creating a class that contains a single float which I then aggregate into my lists), unless someone can tell me how to do it properly.

End Edit

Here's my CreateSessionFactory method, if that helps formulate a
reply...

    private static ISessionFactory CreateSessionFactory() 
    { 
        ISessionFactory sessionFactory = null; 


        const string autoMapExportDir = "AutoMapExport"; 
        if( !Directory.Exists(autoMapExportDir) ) 
            Directory.CreateDirectory(autoMapExportDir); 


        try 
        { 
            var autoPersistenceModel = 
                AutoMap.AssemblyOf<DlsAppOverlordExportRunData>() 
                       .Where(t => t.Namespace == "DlsAppAutomapped") 
                       .Conventions.Add( DefaultCascade.All() ) 
                ; 


            sessionFactory = Fluently.Configure() 
                .Database(SQLiteConfiguration.Standard 
                              .UsingFile(DbFile) 
                              .ShowSql() 
                         ) 
                .Mappings(m => m.AutoMappings.Add(autoPersistenceModel) 
                                             .ExportTo(autoMapExportDir) 
                         ) 
                .ExposeConfiguration(BuildSchema) 
                .BuildSessionFactory() 
                ; 
        } 
        catch (Exception e) 
        { 
            Debug.WriteLine(e); 
        } 


        return sessionFactory; 
    } 

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

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

发布评论

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

评论(4

你的背包 2024-08-17 19:25:05

我可能会做一对多的关系,并使列表成为另一个表...

但也许你需要重新考虑你的对象,是否还有一个可以组成 RawPoint 的 RawX?这将创建一个包含 3 列(ParentID、X、Y)的表。

不连续性来自于想要将列表映射到 RDBMS 中不会非常整齐地放入列中的值。表实际上是他们用来存储数据列表的方法。

这就是使用像 NHibernate 这样的 ORM 的全部意义。当在应用程序中手动执行所有查询和 SQL 组合时,添加表的维护和实施成本很高。使用 NHibernate 成本几乎为 0,因此请利用 RDBMS 的优势,让 NHibernate 消除丑陋。


我看到您在映射数组时遇到问题,首先尝试使用覆盖映射,看看它是否有效,然后如果您希望自动映射工作,您可以创建一个约定覆盖。

.Override<MyType>(map =>
{
    map.HasMany(x => x.RawY).AsList();
})

不确定这是否有效,我需要为这个东西配置一个 nHibernate 测试设置。

I would probably do a one to many relationship and make the list another table...

But maybe you need to rethink your object, is there also a RawX that you could compose into a RawPoint? This would make a table with 3 columns (ParentID, X, Y).

The discontinuity comes from wanting to map a List to a value that in an RDBMS won't go in a column very neatly. A table is really the method that they use to store Lists of data.

This is the whole point of using an ORM like NHibernate. When doing all the querying and SQL composition by hand in your application, adding a table had a high cost in maintenance and implementation. With NHibernate the cost is nearly 0, so take advantage of the strengths of the RDBMS and let NHibernate abstract the ugliness away.


I see your problem with mapping the array, try it with an override mapping first and see if it will work, then you could maybe create a convention override if you want the automap to work.

.Override<MyType>(map =>
{
    map.HasMany(x => x.RawY).AsList();
})

Not sure if that will work, I need to get an nHibernate testing setup configured for this stuff.

千里故人稀 2024-08-17 19:25:05

自从我发布问题后,Fluent NHibernate 团队已经解决了这个问题。

现在,您可以自动映射 C# 值类型(字符串、整数、浮点数等)的 IList。

只需确保您拥有最新版本的 FNH。

编辑

我最近从 FNH 1.0 升级到 FNH 1.3。

此版本还将自动映射数组 - float[]、int[] 等。

似乎将它们映射为 BLOB。我认为这比 IList 更有效,但尚未进行任何分析来确认。

Since I posted my question, the Fluent NHibernate team have fixed this problem.

You can now automap ILists of C# value types (strings, ints, floats, etc).

Just make sure you have a recent version of FNH.

Edit

I recently upgraded from FNH 1.0 to FNH 1.3.

This version will also automap arrays - float[], int[], etc.

Seems to map them as BLOBs. I assume this will be more efficient than ILists, but have not done any profiling to confirm.

谢绝鈎搭 2024-08-17 19:25:05

我最终得到了一个覆盖来工作 - 请参阅代码清单的末尾。关键点是:

  • 一个名为 DlsAppOverlordExportRunDataMap 的新映射类

  • CreateSessionFactory

此外,事实证明(至少在 v. 1.0.0.594 中)Automapping 存在一个非常大的问题 - 映射类(例如 DlsAppOverlordExportRunDataMap)不能与域类位于同一命名空间中(例如 DlsAppOverlordExportRunData)!

否则,NHibernate 将抛出 "NHibernate.MappingException: (XmlDocument)(2,4): XMLvalidation error: ..." ,并且绝对没有任何指示或者真正的问题在哪里。

这可能是一个错误,可能会在 Fluent NHibernate 的更高版本中修复。

namespace DlsAppAutomapped
{
    public class DlsAppOverlordExportRunData
    {
        public virtual int Id { get; set; }

        // Note: List<float> needs overrides in order to be mapped by NHibernate. 
        // See class DlsAppOverlordExportRunDataMap.
        public virtual IList<float> RawY { get; set; } 
    }
}


namespace FrontEnd
{
    // NEW - SET UP THE OVERRIDES
    // Must be in different namespace from DlsAppOverlordExportRunData!!!
    public class DlsAppOverlordExportRunDataMap : IAutoMappingOverride<DlsAppOverlordExportRunData>
    {
        public void Override(AutoMapping<DlsAppOverlordExportRunData> mapping)
        {
            // Creates table called "RawY", with primary key
            // "DlsAppOverlordExportRunData_Id", and numeric column "Value"
            mapping.HasMany(x => x.RawY)
                   .Element("Value");
        }
    }
}

    private static ISessionFactory CreateSessionFactory() 
    { 
        ISessionFactory sessionFactory = null; 


        const string autoMapExportDir = "AutoMapExport"; 
        if( !Directory.Exists(autoMapExportDir) ) 
            Directory.CreateDirectory(autoMapExportDir); 


        try 
        { 
            var autoPersistenceModel = 
                AutoMap.AssemblyOf<DlsAppOverlordExportRunData>() 
                       .Where(t => t.Namespace == "DlsAppAutomapped")

                       // NEW - USE THE OVERRIDES    
                       .UseOverridesFromAssemblyOf<DlsAppOverlordExportRunData>() 

                       .Conventions.Add( DefaultCascade.All() ) 
                ; 


            sessionFactory = Fluently.Configure() 
                .Database(SQLiteConfiguration.Standard 
                              .UsingFile(DbFile) 
                              .ShowSql() 
                         ) 
                .Mappings(m => m.AutoMappings.Add(autoPersistenceModel) 
                                             .ExportTo(autoMapExportDir) 
                         ) 
                .ExposeConfiguration(BuildSchema) 
                .BuildSessionFactory() 
                ; 
        } 
        catch (Exception e) 
        { 
            Debug.WriteLine(e); 
        } 


        return sessionFactory; 
    } 

I eventually got an override to work - see the end of the code listing. The key points are:

  • a new mapping class called DlsAppOverlordExportRunDataMap
  • the addition of a UseOverridesFromAssemblyOf clause in
    CreateSessionFactory

Also, it turns out that (at least with v. 1.0.0.594) there is a very big gotcha with Automapping - the mapping class (e.g. DlsAppOverlordExportRunDataMap) cannot be in the same Namespace as the domain class (e.g. DlsAppOverlordExportRunData)!

Otherwise, NHibernate will throw "NHibernate.MappingException: (XmlDocument)(2,4): XML validation error: ..." , with absolutely no indication of what or where the real problem is.

This is probably a bug, and may be fixed in later versions of Fluent NHibernate.

namespace DlsAppAutomapped
{
    public class DlsAppOverlordExportRunData
    {
        public virtual int Id { get; set; }

        // Note: List<float> needs overrides in order to be mapped by NHibernate. 
        // See class DlsAppOverlordExportRunDataMap.
        public virtual IList<float> RawY { get; set; } 
    }
}


namespace FrontEnd
{
    // NEW - SET UP THE OVERRIDES
    // Must be in different namespace from DlsAppOverlordExportRunData!!!
    public class DlsAppOverlordExportRunDataMap : IAutoMappingOverride<DlsAppOverlordExportRunData>
    {
        public void Override(AutoMapping<DlsAppOverlordExportRunData> mapping)
        {
            // Creates table called "RawY", with primary key
            // "DlsAppOverlordExportRunData_Id", and numeric column "Value"
            mapping.HasMany(x => x.RawY)
                   .Element("Value");
        }
    }
}

    private static ISessionFactory CreateSessionFactory() 
    { 
        ISessionFactory sessionFactory = null; 


        const string autoMapExportDir = "AutoMapExport"; 
        if( !Directory.Exists(autoMapExportDir) ) 
            Directory.CreateDirectory(autoMapExportDir); 


        try 
        { 
            var autoPersistenceModel = 
                AutoMap.AssemblyOf<DlsAppOverlordExportRunData>() 
                       .Where(t => t.Namespace == "DlsAppAutomapped")

                       // NEW - USE THE OVERRIDES    
                       .UseOverridesFromAssemblyOf<DlsAppOverlordExportRunData>() 

                       .Conventions.Add( DefaultCascade.All() ) 
                ; 


            sessionFactory = Fluently.Configure() 
                .Database(SQLiteConfiguration.Standard 
                              .UsingFile(DbFile) 
                              .ShowSql() 
                         ) 
                .Mappings(m => m.AutoMappings.Add(autoPersistenceModel) 
                                             .ExportTo(autoMapExportDir) 
                         ) 
                .ExposeConfiguration(BuildSchema) 
                .BuildSessionFactory() 
                ; 
        } 
        catch (Exception e) 
        { 
            Debug.WriteLine(e); 
        } 


        return sessionFactory; 
    } 
撩人痒 2024-08-17 19:25:05

在这里或 Fluent NHibernate 邮件列表上没有得到任何实际有效的答案,所以这就是我所做的。

这听起来像是一个可怕的黑客,但它确实有效。 (它是否会扩展到大型数据集还有待观察)。

首先,我在一个类中包装了一个浮点属性(称为 Value):

// Hack - need to embed simple types in a class before NHibernate
// will map them
public class MappableFloat
{
    public virtual int Id { get; private set; }
    public virtual float Value { get; set; }
}

然后我在其他需要浮点列表的类中声明属性,例如

public virtual IList<MappableFloat> RawYMappable { get; set; }

NHibernate 创建一个带有多个外键的数据库表,例如

create table "MappableFloat" (
    Id  integer,
   Value NUMERIC,
   DlsAppOverlordExportRunData_Id INTEGER,
   DlsAppOverlordExportData_Id INTEGER,
   primary key (Id)
)

Didn't get any answers here or on the Fluent NHibernate mailing list that actually worked, so here's what I did.

It smells like a horrible hack, but it works. (Whether it will scale up to large data sets remains to be seen).

First, I wrapped a float property (called Value) in a class:

// Hack - need to embed simple types in a class before NHibernate
// will map them
public class MappableFloat
{
    public virtual int Id { get; private set; }
    public virtual float Value { get; set; }
}

I then declare the properties in other classes that need to be Lists of floats e.g.

public virtual IList<MappableFloat> RawYMappable { get; set; }

NHibernate creates a single database table, with multiple foreign keys, e.g.

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