Domanda

Quando mai si imposta un valore stringa in fluente NHibernate imposta alwasy DB Vales a nvarchar (255), ho bisogno di memorizzare un sacco di lunga stringa che si basano su input degli utenti e 255 è impraticabile.

Giusto per aggiungere questo è un problema con l'automapper come io sto usando fluente NHibernate per creare il database.

È stato utile?

Soluzione

Aggiungere questa convenzione imposterà la lunghezza di default per le proprietà di stringa a 10000. Come altri hanno notato, questa sarà una colonna 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);
    }
}

Convenzioni possono essere aggiunti a una configurazione Automap in questo modo:

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

Per ulteriori informazioni, vedere Convenzioni nel wiki Fluent NHibernate.

Altri suggerimenti

Impostazione della lunghezza di qualcosa di più di 4001 genererà un nvarchar (max) ...

.WithLengthOf(10000);

Vedi qui per maggiori dettagli ...

http://serialseb.blogspot.com/2009/ 01 / fluente-NHibernate-e-nvarcharmax.html

Con Fluent NHibernate Automapper, ci si accorge subito che il comportamento out-of-the-box per le colonne varchar è proprio l'ideale. In primo luogo si scopre che ogni proprietà di stringa è stato esportato come varchar (255) e avete bisogno di fare una colonna di essere varchar (max). Ma idealmente, che non avrebbe dovuto fare ogni stringa di un varchar (max), giusto? Quindi si scende percorso che ben tracciato di trovare il modo migliore per esercitare il controllo sul processo senza rompere fuori dai vari modelli eleganti in gioco ...

Se si desidera avere le colonne risultante banca dati varchar specificati in diverse lunghezze, si guarda alle classi di convenzione per farlo accadere. Si potrebbe provare a creare le condizioni specifiche del nome o in generale usa un certo modello di denominazione che avete rilevato all'interno della vostra classe di convenzione.

Nessuno dei due è l'ideale. Il sovraccarico un nome allo scopo di indicare una specifica destinazione in un'altra parte del codice è unfortunate- tuo nome dovrebbe essere solo un nome. Né si dovrebbe avere per modificare il codice convenzione ogni volta che è necessario aggiungere o modificare una proprietà di classe limitata lunghezza. Così come si può scrivere una classe convenzione che offre un controllo e prevede che il controllo in modo semplice ed elegante?

Sarebbe dolce se si può solo decora la vostra proprietà come ho fatto per la proprietà Body qui:

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

Se questo potrebbe funzionare, avremmo il controllo su ogni stringa in modo indipendente, e che saremmo stati in grado di specificare direttamente nella nostra entità.

Prima di iniziare un vortice sulla separazione della base di dati dall'applicazione, vorrei sottolineare che questo non è specificamente una direttiva di database (ho fatto un punto di non chiamare l'attributo 'Varchar'). Io preferisco caratterizzare questo come un aumento del System.string, e nel mio piccolo universo Sono felice con quello. Linea di fondo, voglio una convenienza!

Per fare questo, abbiamo bisogno di definire la decorazione che vogliamo usare:

using System;
namespace MyDomain.DBDecorations
{

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

Infine, abbiamo bisogno di usare una convenzione lunghezza della stringa da usare decorazione proprietà dell'entità. Questa parte non può sembrare bella, ma fa il lavoro, e la buona notizia è che non si deve guardare di nuovo!

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

Aggiungi questa convenzione per la configurazione automapping e il gioco è fatto it- ogni volta che si desidera una lunghezza specifica per portare durante ExportSchema, ora si può solo decorare la proprietà della stringa -e solo tale diritto proprietà- nella vostra entità!

Uno dei modi coerente che ho trovato è:

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

in cui il VarcharMax e le classi sono

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

Ciao mi sono imbattuto in questa domanda, con lo stesso problema. Ho un po ' sicuro modo di farlo come io non voglio tutti i campi stringa di avere 10000 caratteri di default.

In primo luogo mi registro NHibernate fluente con alcune modifiche locali

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

Il mio Mappatura classe di override si presenta così:

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

Questa è necessaria solo per piccolo sottogruppo di soggetti con valori di testo lunghi. Forse qualche altra cosa troveranno questo utile?

Probabilmente si sta utilizzando " NHibernate validatore " pure. Se sì, Fluent NHibernate prenderà in considerazione tutte le annotazioni di dati relativi validatore NHibernate automaticamente, tra cui la lunghezza della stringa, non nullo, ecc.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top