How do I get fluent nhibernate to create a varbinary(max) field in sql server
Asked Answered
A

6

14

How can I get fluent nhibernate to create a varbinary field in a sql server 2005 table that uses a field size of varbinary(max)? At the moment I always get a default of varbinary(8000), which isn't big enough as i'm going to be storing image files.

I've tried using CAstle.ActiveRecord but havent had any success yet.

 [ActiveRecord]
 public class MyFile : Entity
{
    public virtual string FileName { get; set; }
    public virtual string FileType { get; set; }
    public virtual int FileVersion { get; set; }
    public virtual int FileLength { get; set; }

    [Property(ColumnType = "BinaryBlob", SqlType = "VARBINARY(MAX)")]
    public virtual byte[] FileData { get; set; }   
}

Been failing at finding a solution for hours now, so thanks in advance

czk

Aboral answered 8/7, 2009 at 13:59 Comment(0)
G
10

I'm not sure why your ActiveRecord example is not working, but there you might try setting the length of the column.

With Fluent NHibernate, you should be able to do

Map(x => x.FileData)
    .WithLengthOf(2147483647)
Gabriellia answered 8/7, 2009 at 15:33 Comment(0)
P
5

I was having a similar issue with SQL FileStream and Fluent NHibernate where my BLOB writes were truncating at 8000 bytes. The following syntax finally fixed the problem:

Map(x => x.Bytes)
  .CustomSqlType("VARBINARY (MAX) FILESTREAM")
  .Length(2147483647)
  .Not.Nullable();
Peonir answered 12/6, 2012 at 21:52 Comment(1)
int.MaxValue might be a nicer way of expressing the magic number. As in .Length(int.MaxValue)Marlie
C
2

In the mapping use:

Map(x => x.FileData).CustomSqlType("VARBINARY(MAX)");

Classical answered 14/8, 2010 at 18:21 Comment(1)
Using NHibernate version 3.1.0.4000 with FluentNhibernate version 1.2.0.712 this did not work. This worked for me: Map(x => x.FileData).CustomType("BinaryBlob").Trixi
C
2

You need an auto-mapping override:

public class MyFileMapOverride : IAutoMappingOverride<MyFile>
{
    public void Override( AutoMapping<MyFile> mapping )
    {
        mapping.Map( x => x.FileData ).Length( int.MaxValue );
    }
}

Since you're using Castle, you can tell it to wire up NHibernate with your mappings in your NHibernateInstaller:

public void Install( IWindsorContainer container, IConfigurationStore store )
{
    container.Register( Component.For<ISessionFactory>()
                                 .UsingFactoryMethod( k => BuildSessionFactory() )
                                 .Named( "MySessionFactory" ) );

    // Do other stuff...
}

private ISessionFactory BuildSessionFactory()
{
    var mappings = AutoMap.AssemblyOf<MyFile>()
                          .IgnoreBase( typeof(Entity) )
                          .UseOverridesFromAssemblyOf<MyFileMapOverride>();

    var configuration = ConfigurationUtility
        .CreateConfiguration<WebSessionContext, DefaultProxyFactoryFactory>(
            "MyDbConnection",
            ConfigurationUtility.ForMsSql,
            mappings,
            NHibernateConfiguration.GetConfigurationPath() );

    return configuration.BuildSessionFactory();
}
Clariceclarie answered 26/9, 2014 at 17:38 Comment(0)
A
1

AFAIK, there is no such thing in Fluent NHibernate as "max", however, if you set the allowed length of a column to a real big value, it should work fine. You can check MSDN for what number max means for each datatype in SQL Server, although it may mean some very different number in others.

I used reflector and found this:

public MsSql2005Dialect()
{
    base.RegisterColumnType(DbType.String, 0x3fffffff, "NVARCHAR(MAX)");
    base.RegisterColumnType(DbType.AnsiString, 0x7fffffff, "VARCHAR(MAX)");
    base.RegisterColumnType(DbType.Binary, 0x7fffffff, "VARBINARY(MAX)");
}

So, it seems that NHibernate creates max by default? Still, Fluent doesn't. (Although I don't know why.)

With the Auto mapping feature, you can use conventions to achieve it.

Example:

var cfg = new Configuration();

var persistenceModel = new AutoPersistenceModel();
persistenceModel.Conventions.Add(
    new PropertyConvention(),
    new ReferenceConvention(),
    new HasManyConvention(),
    ConventionBuilder.Property.Always(delegate(IPropertyInstance instance)
    {
        if (instance.Property.PropertyType == typeof(string))
            instance.Length(16000);
        else if (instance.Property.PropertyType == typeof(byte[]))
            instance.Length(30000000);
    }));
persistenceModel.AddTypeSource(new AssemblyTypeSource(Assembly.GetExecutingAssembly()));
persistenceModel.Where(t => t.Namespace.EndsWith("Entities"));

cfg.AddAutoMappings(persistenceModel);
return cfg.BuildSessionFactory();

For me, this suffices, but you can always use larger numbers.

If you don't use automapping, Dan Fitch's solution is the way to go, I guess.

Argo answered 7/5, 2010 at 12:5 Comment(0)
A
0

First off, I (annoyingly) put the map file into the core project rather than the data project.

I still couldn't get it to work with a map file, but i wrote an xml file instead, writing the file length in - thanks for that Dan

 <property name="FileName"/>
 <property name="FileType"/>
 <property name="VersionNo"/>
 <property name="FileLength"/>
 <property name="FileData" length="2147483647"/>
Aboral answered 14/7, 2009 at 16:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.