40

流暢なNHibernateで文字列値を設定すると、常にDB値がNvarchar(255)に設定されます。ユーザー入力に基づく非常に多くの長い文字列を格納する必要があり、255は実用的ではありません。

これを追加するだけで、データベースを構築するために流暢なNHibernateを使用しているため、オートマッパーの問題になります。

4

6 に答える 6

33

この規則を追加すると、文字列プロパティのデフォルトの長さが10000に設定されます。他の人が指摘しているように、これは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);
    }
}

次のように、自動マップ構成に規則を追加できます。

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

詳細については、FluentNHibernatewikiの規則を参照してください。

于 2010-02-26T16:47:55.980 に答える
17

長さを4001を超える値に設定すると、NVarchar(MAX)が生成されます。

.WithLengthOf(10000);

詳細については、こちらをご覧ください...

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

于 2010-02-26T16:34:42.627 に答える
6

Fluent Nhibernate Automapperを使用すると、varchar列のすぐに使用できる動作が理想的とは言えないことがすぐにわかります。最初に、すべての文字列プロパティがvarchar(255)としてエクスポートされ、列をvarchar(max)にする必要があることがわかります。しかし、理想的には、すべての文字列をvarchar(max)にする必要はありませんよね?それで、あなたは、プレー中のさまざまなエレガントなパターンから抜け出すことなく、プロセスを制御するための最良の方法を見つけるという、よく踏まれた道を進みます...

結果のデータベースvarchar列をさまざまな長さで指定したい場合は、それを実現するために規則クラスを調べます。名前固有の条件を作成するか、通常、コンベンションクラス内で検出した名前付けパターンを使用してみてください。

どちらも理想的ではありません。コードの別の部分で意図された仕様を示す目的で名前をオーバーロードするのは残念です。名前は単なる名前である必要があります。また、制限された長さのクラスプロパティを追加または変更する必要があるたびに、規則コードを変更する必要はありません。では、コントロールを提供し、そのコントロールをシンプルでエレガントな方法で提供するコンベンションクラスをどのように作成できますか?

ここでBodyプロパティに対して行ったように、プロパティを装飾することができれば、それはすばらしいことです。

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

これが機能する場合は、各文字列を個別に制御でき、エンティティで直接指定できます。

データベースをアプリケーションから分離するという大混乱を始める前に、これは特にデータベースディレクティブではないことを指摘しておきます(属性「Varchar」を呼び出さないことを強調しました)。私はこれをSystem.stringの拡張として特徴付けることを好み、私自身の小さな宇宙ではそれに満足しています。結論として、私は便利が欲しいです!

これを行うには、使用する装飾を定義する必要があります。

using System;
namespace MyDomain.DBDecorations
{

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

最後に、エンティティのプロパティ装飾を使用するには、文字列の長さの規則を使用する必要があります。この部分はきれいに見えないかもしれませんが、それは仕事をします、そして良いニュースはあなたがそれをもう一度見る必要がないということです!

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

この規則を自動マッピング構成に追加すると、ExportSchema中に特定の長さを生成する場合はいつでも、文字列プロパティ(およびそのプロパティのみ)をエンティティ内で直接装飾できます。

于 2011-04-10T00:17:09.747 に答える
3

私が見つけた一貫した方法の1つは次のとおりです。

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

VarcharMaxとクラスは

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; }
    }
}
于 2012-06-28T14:01:46.857 に答える
2

こんにちは私は同じ問題でこの質問に出くわしました。すべての文字列フィールドにデフォルトで10000文字を使用したくないので、少し安全な方法があります。

まず、いくつかのオーバーライドを使用して流暢なnhibernateを登録します

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

私のMappingオーバーライドクラスは次のようになります。

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

これは、長いテキスト値を持つエンティティの小さなサブセットにのみ必要です。多分他の誰かがこれが役に立つと思うでしょうか?

于 2013-08-30T21:28:17.397 に答える
1

おそらく、「NHibernateバリデーター」も使用しています。はいの場合、Fluent NHibernateは、nullではなく文字列の長さなど、NHibernateバリデーターに関連するすべてのデータ注釈を自動的に考慮します。

于 2011-11-12T20:17:04.743 に答える