Need to Automap List<float> or float[]

158 views
Skip to first unread message

tbushell

unread,
Nov 6, 2009, 4:13:12 PM11/6/09
to Fluent NHibernate
Having successfully gotten a sample program working, I'm now starting
to do Real Work - 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.

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).

Thanks,

-Tom

PS 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;
}







tbushell

unread,
Nov 9, 2009, 4:25:49 PM11/9/09
to Fluent NHibernate
I've studied the code in http://stackoverflow.com/questions/606607/mapping-collection-of-strings-with-nhibernate.

Also, 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.

-Tom
> ---------------------------------------------------------------------------­------------

James Gregory

unread,
Nov 10, 2009, 3:55:39 AM11/10/09
to fluent-n...@googlegroups.com
I can't remember off the top of my head whether we can detect lists of primitive types with the automapper; I don't think there's any technical reason why we wouldn't, it just might not be supported.

What you can do until one of us can get you a better answer is to use an automapping override for this specific case, which would let you control how the automapper is treating your list.

Something like:

public class ClassWithPrimitiveListOverride : IAutoMappingOverride<ClassWithPrimitiveList>
{
  public override void Override(AutoMapping<ClassWithPrimitiveList> mapping)
  {
     m.HasMany(x => x. RawY)
       .Element("columnName");

tbushell

unread,
Nov 10, 2009, 11:44:40 AM11/10/09
to Fluent NHibernate
James wrote:

>I can't remember off the top of my head whether we can detect lists of
>primitive types with the automapper;

No, you don't - throws a "No persister for System.Single" exception
for IList<float>, IIRC. Although some of the test cases imply that
you do - search for "ListOfSimpleChildren".

I really, really, REALLY think you should support this out of the box
- it's an obvious thing to want to do.

Thanks for your suggestion, but it does not work (see below). Think
I'm going to have to cut my losses and wrap my floats (and any other
primitive types) in their own classes before aggregating into lists.
I consider this a horrendous hack, but it's the only thing that's
worked so far!

In any case, in the hope that you may be able to see what's wrong,
here's what I did...

I added this to the Examples.FirstProject that comes with the Fluent
source code:

public class Product
{
...
public virtual IList<float> ListFloats { get; set; }
...
}

public class ProductOverride : IAutoMappingOverride<Product>
{
public void Override(AutoMapping<Product> mapping)
{
mapping.HasMany(x => x.ListFloats)
.Element("columnName");
}
}


And this to my CreateSessionFactory:

.UseOverridesFromAssemblyOf<ProductOverride>()

Here's what I get when I run:

Inner Exception:

{"The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has
incomplete content. List of possible elements expected: 'meta,
subselect, cache, synchronize, comment, tuplizer, id, composite-id' in
namespace 'urn:nhibernate-mapping-2.2'."}


Mapping file: - Examples.FirstProject.Entities.ProductOverride.hbm.xml

- <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-
access="property" auto-import="true" default-cascade="all" default-
lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2"
name="Examples.FirstProject.Entities.ProductOverride,
Examples.FirstProject, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null" table="`ProductOverride`" />
</hibernate-mapping>

If you need more info, please let me know.

-Tom

Asbjørn Ulsberg

unread,
Nov 18, 2009, 6:17:57 PM11/18/09
to fluent-n...@googlegroups.com
On Fri, 06 Nov 2009 22:13:12 +0100, tbushell <tbus...@bic.com> wrote:

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

The default procedure would be to map all lists, arrays, etc., as
"one-to-many", e.g. References() in FNH. However, that requires each of
your float values to be stored as a separate row in their own table, which
for this purpose doesn't sound quite optimal.

> 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.

Indeed; a blob is the correct way to store arbitrary data like arrays.

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

I'm no NH expert, but I expect that you need to provide NHibernate with a
way to convert back and forth between float[] and the blob in the
database. For that, you need to implement your own IUserType. See the
following URLs for examples on how to implement your own IUserType:

<http://www.martinwilley.com/net/code/nhibernate/usertype.html>
<http://weblogs.asp.net/ricardoperes/archive/2009/09/17/nhibernate-image-user-type.aspx>

If you get this working, please post the code of your IUserType. Perhaps
something can be done within FNH to automatically map arrays of value
types as single column blobs instead of one-to-many's.

> 1. How can I make this work with Automapping?

You probably need to create an override for each class that have these
arrays, or perhaps you can decorate them with a custom attribute like
[HasArrayBlob] and create an override for the bunch of them via the
attribute.

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

For this use, I'd say arrays mapped as single column blobs in the
database. Mapping this (with list or an array) as a one-to-many doesn't
sound like what you're aiming for.

--
Asbjørn Ulsberg -=|=- asb...@ulsberg.no
«He's a loathsome offensive brute, yet I can't look away»

tbushell

unread,
Nov 19, 2009, 11:39:32 AM11/19/09
to Fluent NHibernate
Asbjorn,

> database. For that, you need to implement your own IUserType. See the  
> following URLs for examples on how to implement your own IUserType:
>
> <http://www.martinwilley.com/net/code/nhibernate/usertype.html>
> <http://weblogs.asp.net/ricardoperes/archive/2009/09/17/nhibernate-ima...>

Thanks for the links, especially the first one


> If you get this working, please post the code of your IUserType. Perhaps  
> something can be done within FNH to automatically map arrays of value  
> types as single column blobs instead of one-to-many's.

I suspect so, but no one as provided any samples, and my own
experiments have been miserable failures.



> Mapping this (with list or an array) as a one-to-many doesn't  
> sound like what you're aiming for.

Unfortunately, that's what I ended up doing, but I can't say I like
it. I provide some sample code in an answer to my own question on
Stack Overflow:

http://stackoverflow.com/questions/1690775/how-do-you-automap-listfloat-or-float-with-fluent-nhibernate

I'll probably look into your suggestions - seems like a better
approach in the long run.

Thanks again,

-Tom

Reply all
Reply to author
Forward
0 new messages