40 votes

Remplacement pour NHibernate fluent pour de longues chaînes de texte de type nvarchar(MAX) pas de type nvarchar(255)

Lorsque vous définissez une valeur de chaîne dans NHibernate fluent il toujours ensembles de la DB vallées de type Nvarchar(255), j'ai besoin de stocker beaucoup de très longue chaîne qui sont basées sur les entrées de l'utilisateur et 255 est pas pratique.

Juste pour ajouter, c'est un problème avec le automapper que j'utilise couramment NHibernate pour construire la base de données.

33voto

Lachlan Roche Points 16456

L'ajout de cette convention sera de définir la durée par défaut pour les propriétés de la chaîne de 10000. Comme d'autres l'ont noté, ce sera un nvarchar(max) de la colonne.

public class StringColumnLengthConvention : IPropertyConvention, IPropertyConventionAcceptance
{
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Type == typeof(string)).Expect(x => x.Length == 0);
    }
    public void Apply(IPropertyInstance instance)
    {
        instance.Length(10000);
    }
}

Des Conventions peuvent être ajoutés à un automap de configuration comme ceci:

Fluently.Configure()
    .Mappings( m =>
        m.AutoMappings.Add( AutoMap.AssemblyOf<Foo>()
        .Conventions.Add<StringColumnLengthConvention >()))

Pour plus d'informations, voir Conventions dans la courant de NHibernate wiki.

17voto

Russell Giddings Points 2609

Réglage de la longueur de quelque chose de plus 4001 va générer un type NVarchar(MAX)...

.WithLengthOf(10000);

Voir ici pour plus de détail...

http://serialseb.blogspot.com/2009/01/fluent-nhibernate-and-nvarcharmax.html

6voto

Benjamin Johnson Points 157

Avec Nhibernate Fluent Automapper, on se rend vite compte que la dehors-de-le-boîte de comportement pour les colonnes varchar est pas l'idéal. Tout d'abord vous découvrir que chaque chaîne de propriété a été exporté en tant que varchar(255) et vous avez besoin de faire une colonne de type varchar(max). Mais, idéalement, vous ne devriez pas avoir à faire de chaque chaîne de type varchar(max), droit? Si vous vous dirigez vers le bas que bien battus de chemin de trouver la meilleure façon d'exercer un contrôle sur le processus, sans briser les différents modèles élégants à jouer...

Si vous voulez avoir votre base de données varchar colonnes spécifiées, à des longueurs différentes, vous regardez à la convention des classes pour y arriver. Vous pouvez essayer de créer le nom spécifique de conditions ou de façon générale, l'utilisation de certains modèle de nommage que vous avez détecté à l'intérieur de votre convention de classe.

Aucune n'est idéale. La surcharge d'un nom dans le but d'indiquer une intention de spec dans une autre partie du code est malheureux, votre nom doit être juste un nom. Vous ne devriez pas avoir à modifier le code de la convention chaque fois que vous avez besoin d'ajouter ou de modifier une limitée-durée de propriété de la classe. Alors, comment pouvez-vous écrire une convention de classe qui vous donne le contrôle et prévoit que le contrôle dans une façon simple et élégante?

Ce serait gentil si vous pouvez simplement décorer votre propriété comme je l'ai fait pour le Corps bien ici:

using System; 
using MyDomain.DBDecorations;

namespace MyDomain.Entities {
    [Serializable]
    public class Message
    {
        public virtual string MessageId { get; set; }

        [StringLength(4000)] public virtual string Body { get; set; }
    }
}

Si cela pourrait fonctionner, nous aimerions avoir le contrôle sur chaque chaîne de façon indépendante, et nous serions en mesure de le spécifier directement dans notre entité.

Avant que je commence un maelström sur la séparation de la base de données de l'application, permettez-moi de souligner que ce n'est pas spécialement une base de données de la directive (j'ai fait un point de ne pas appeler l'attribut "Varchar"). Je préfère caractériser ce que l'augmentation de la Système.chaîne, et dans mon petit univers j'en suis heureux. Bas de ligne, je veux une commodité!

Pour ce faire, nous avons besoin de définir la décoration nous voulons utiliser:

using System;
namespace MyDomain.DBDecorations
{

    [AttributeUsage(AttributeTargets.Property)]
    public class StringLength : System.Attribute
    {
        public int Length = 0;
        public StringLength(int taggedStrLength)
        {
            Length = taggedStrLength;
        }
    }
}

Enfin, nous avons besoin d'utiliser une chaîne de caractères de longueur de la convention pour l'emploi de l'entité est la décoration de la propriété. Cette partie peut ne pas sembler peu, mais il fait le travail, et la bonne nouvelle est que vous n'aurez pas à le regarder de nouveau!

StringColumnLengthConvention.cs:

using System.Reflection;
using FluentNHibernate.Conventions;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Inspections;
using FluentNHibernate.Conventions.Instances;

namespace MyMappings
{
    public class StringColumnLengthConvention : IPropertyConvention, IPropertyConventionAcceptance
    {
        public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) { criteria.Expect(x => x.Type == typeof(string)).Expect(x => x.Length == 0); }
        public void Apply(IPropertyInstance instance)
        {
            int leng = 255;

            MemberInfo[] myMemberInfos = ((PropertyInstance)(instance)).EntityType.GetMember(instance.Name);
            if (myMemberInfos.Length > 0)
            {
                object[] myCustomAttrs = myMemberInfos[0].GetCustomAttributes(false);
                if (myCustomAttrs.Length > 0)
                {
                    if (myCustomAttrs[0] is MyDomain.DBDecorations.StringLength)
                    {
                        leng = ((MyDomain.DBDecorations.StringLength)(myCustomAttrs[0])).Length;
                    }
                }
            }
            instance.Length(leng);
        }
    }
}

Ajouter cette convention à votre mappant automatiquement la configuration et là vous l'avez - chaque fois que vous voulez une longueur spécifique de résultat au cours de ExportSchema, maintenant vous pouvez simplement décorer la propriété de chaîne -et uniquement celle du droit de propriété dans votre entité!

3voto

Daniel Bahmani Points 443

L'une des manière à ce que j'ai trouvé est:

Map(x => x.LongText, "LongText").CustomType<VarcharMax>().Nullable();

dans lequel le VarcharMax et les classes sont

public class VarcharMax : BaseImmutableUserType<String>
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        return  (string)NHibernateUtil.String.NullSafeGet(rs, names[0]);
    }
    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        //Change the size of the parameter
        ((IDbDataParameter)cmd.Parameters[index]).Size = int.MaxValue;
        NHibernateUtil.String.NullSafeSet(cmd, value, index);
    }
    public override SqlType[] SqlTypes
    {
        get { return new[] { new SqlType(DbType.String) }; }
    }
}

public abstract class BaseImmutableUserType<T> : NHibernate.UserTypes.IUserType
{
    public abstract object NullSafeGet(IDataReader rs, string[] names, object owner);
    public abstract void NullSafeSet(IDbCommand cmd, object value, int index);
    public abstract SqlType[] SqlTypes { get; }

    public new bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y))
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }

        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public Type ReturnedType
    {
        get { return typeof(T); }
    }

    public bool IsMutable
    {
        get { return false; }
    }
}

1voto

VahidN Points 3905

Probablement, vous êtes à l'aide de "NHibernate validateur" ainsi. Si oui, NHibernate Fluent tiendra compte de tous les NHibernate programme de validation des données connexes automatiquement les annotations, y compris la longueur de la chaîne, n'est pas null, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X