[英]Override for fluent NHibernate for long text strings nvarchar(MAX) not nvarchar(255)
當你在 fluent NHibernate 中設置一個字符串值時,它總是將 DB 值設置為 Nvarchar(255),我需要存儲相當多的基於用戶輸入的長字符串,而 255 是不切實際的。
只是補充一下,這是自動映射器的一個問題,因為我正在使用流利的 NHibernate 來構建數據庫。
添加此約定會將字符串屬性的默認長度設置為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 >()))
有關更多信息,請參閱Fluent NHibernate wiki中的約定 。
將長度設置為4001以上將生成NVarchar(MAX)...
.WithLengthOf(10000);
有關詳細信息,請參見此處
http://serialseb.blogspot.com/2009/01/fluent-nhibernate-and-nvarcharmax.html
使用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期間生成特定長度,現在您只需裝飾字符串屬性 - 並且只能在您的實體中裝飾該屬性!
我找到的一致方法是:
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; }
}
}
嗨,我遇到了這個問題,同樣的問題。 我有一個更安全的方法,因為我不希望所有字符串字段默認有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);
}
}
這僅適用於具有長文本值的小實體子集。 也許其他人會發現這有用嗎?
可能你也在使用“ NHibernate驗證器 ”。 如果是,Fluent NHibernate將自動考慮所有NHibernate驗證器相關數據注釋,包括字符串長度,非空等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.