Question

Chaque fois que vous définissez une valeur de chaîne dans Fluent NHibernate il définit alwasy DB vales à Nvarchar (255), je dois stocker beaucoup de très longue chaîne qui sont basées sur des données de l'utilisateur et 255 est peu pratique.

Il suffit d'ajouter ceci est un problème avec le automapper que j'utilise NHibernate couramment pour construire la base de données.

Était-ce utile?

La solution

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

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

Conventions peuvent être ajoutées à une configuration Automap comme ceci:

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

Pour plus d'informations, consultez dans le wiki Fluent NHibernate.

Autres conseils

Réglage de la longueur à quoi que ce soit sur 4001 va générer un nvarchar (MAX) ...

.WithLengthOf(10000);

Voir ici pour plus de détails ...

http://serialseb.blogspot.com/2009/ 01 / NHibernate-et-nvarcharmax.html couramment

Courant Nhibernate Automapper, on se rend compte rapidement que le comportement hors-the-box pour les colonnes varchar est moins qu'idéal. D'abord, vous découvrez que chaque propriété de chaîne a été exportée en tant que varchar (255) et vous avez besoin de faire une colonne à varchar (max). Mais idéalement, vous ne pas avoir à faire toutes les chaînes varchar (max), non? Donc, vous vous dirigez vers le bas chemin bien foulé de trouver la meilleure façon d'exercer un contrôle sur le processus sans sortir des différents modèles élégants en jeu ...

Si vous voulez avoir vos colonnes varchar de base de données résultant spécifiées à différentes longueurs, vous regardez les classes de congrès pour y arriver. Vous pouvez essayer de créer des conditions spécifiques au nom ou utilisent généralement un certain modèle de nom que vous avez détecté dans votre classe convention.

Ni est idéal. Surcharger un nom dans le but d'indiquer une spécification prévue dans une autre partie du code est unfortunate- votre nom doit être juste un nom. si vous avez ni à modifier le code de la convention chaque fois que vous devez ajouter ou modifier une propriété de classe longueur limitée. Alors, comment d'une manière simple et élégante, vous pouvez écrire une classe de convention qui vous permet de contrôler et prévoit que le contrôle?

Il serait doux si vous pouvez simplement décorez votre propriété comme je l'ai fait pour le bien du corps 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 aurions le contrôle sur chaque chaîne indépendamment, et nous serions en mesure de préciser directement dans notre entité.

Avant de commencer 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écifiquement une directive de base de données (j'ai fait un point de ne pas appeler l'attribut « Varchar »). Je préfère qualifier cela comme une augmentation de la System.string, et dans mon petit univers, je suis heureux. En bout de ligne, je veux une commodité!

Pour ce faire, nous devons définir la décoration que 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 devons utiliser une convention de longueur de chaîne à utiliser la décoration de la propriété de l'entité. Cette partie peut ne pas sembler assez, mais il fait le travail, et les bonnes nouvelles sont que vous n'aurez pas à regarder à 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 configuration AutoMapping et il vous it- chaque fois que vous voulez une longueur spécifique pour résultat pendant ExportSchema, maintenant, vous pouvez simplement décorer la propriété de chaîne -et seulement ce droit dans votre entité propriété-!

L'une des manière cohérente 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; }
    }
}

Salut je suis tombé sur cette question, avec le même problème. J'ai un peu plus en sécurité façon de le faire que je ne veux pas tous les champs de chaîne pour avoir 10000 caractères par défaut.

Tout d'abord j'enregistrer NHibernate couramment avec quelques remplacements

...//snip
....Mappings(m => m.AutoMappings.Add(
                    AutoMap.AssemblyOf<Account>()
                     //Use my mapping overrides here 
                    .UseOverridesFromAssemblyOf<MyMappingOverride>()
                    .Conventions.Add(new MyConventions()).IgnoreBase<Entity>
                ))

Ma Mapping classe override ressemble à ceci:

public class MyMappingOverride : IAutoMappingOverride<MyClass> {
       public void Override(AutoMapping<MyClass> mapping) {
           mapping.Map(x => x.LongName).Length(765);
       }
}

Ceci est nécessaire uniquement pour les petites sous-ensemble d'entités avec des valeurs de texte long. Peut-être un autre trouveront cela utile?

Probablement que vous utilisez " NHibernate validateur " ainsi. Si oui, Fluent NHibernate examinera toutes les annotations de données liées au validateur NHibernate automatiquement, y compris la longueur de chaîne, non null, etc.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top