前言:
以下內容Fluent Nhibernate官方wiki里面都有,並且都是基本的用法,只是對於剛剛使用時遇到的問題點做一下整理,希望可以對那些不喜歡看官方help的同學有所幫助:)
目錄:
-
數據庫配置
-
FluentMappings和AutoMappings混合使用
-
枚舉類型配置
-
生成sql日志配置
-
AutoMap時不允許Nhibernate自動生成Id
-
AutoMap時配置Image字段長度
數據庫配置
1 private static ISessionFactory CreateSessionFactory() 2 { 3 return Fluently.Configure() 4 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 5 6 }
FluentMappings和AutoMappings混合使用
Fluent NHibernate的AutoMapping功能還是極大的提高開發效率的,只要滿足基本的默認規則就行,在建立新項目時尤其好用。但在需要使用已存在的表或者是不滿足默認規則的時候就可能需要自動以Map來實現了。配置代碼如下:
1 public static FluentConfiguration GetConfiguration() 2 { 3 var model = AutoMap.Assembly(Assembly.Load("EntApp.ShinFlow.Data")). 4 Where(t => t.Namespace == "EntApp.ShinFlow.Data.Model") 5 .IgnoreBase<BaseEntity>() 6 ; 7 8 return Fluently.Configure() 9 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 10 .Mappings(m=>{ 11 m.AutoMappings.Add(model); 12 m.FluentMappings.AddFromAssemblyOf<EntApp.ShinFlow.Data.CustomModel.User>(); 13 }); 14 15 }
其中第3行是加載自動Map的Assembly,第4行為只有名稱空間為EntApp.ShinFlow.Data.Model的Model才自動Map。
第12行是常規的FluentMapping,我這里使用名稱空間來區分哪些實體類可以進行AotoMap,FluentNibernate還提供了其他條件,比如type,basetype等等屬性。
枚舉類型配置
這個功能是我最喜歡的,因為以前用Entity framework時沒辦法支持,每次都要變相的使用,現在Nhibernate可方便的使用。
默認條件下Nhibernate就支持枚舉類型,但會取枚舉的.ToString進行存儲,往往在數據庫設計的時候希望存儲枚舉對應的int值,這就需要重寫Nhibernate的IUserTypeConvention接口來實現
1 public class EnumConvention : IUserTypeConvention 2 { 3 public void Apply(IPropertyInstance instance) 4 { 5 instance.CustomType(instance.Property.PropertyType); 6 } 7 8 public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) 9 { 10 criteria.Expect(x => x.Property.PropertyType.IsEnum); 11 } 12 public bool Accept(Type type) 13 { 14 return type.IsEnum; 15 } 16 }
然后在FluentConfiguration環節配置上。
1 public static FluentConfiguration GetConfiguration() 2 { 3 var model = AutoMap.Assembly(Assembly.Load("EntApp.ShinFlow.Data")). 4 Where(t => t.Namespace == "EntApp.ShinFlow.Data.Model") 5 .IgnoreBase<BaseEntity>() 6 .Conventions.AddFromAssemblyOf<EnumConvention>(); 7 8 return Fluently.Configure() 9 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 10 .Mappings(m=>{ 11 m.AutoMappings.Add(model); 12 m.FluentMappings.AddFromAssemblyOf<EntApp.ShinFlow.Data.CustomModel.User>(); 13 }); 14 }
在如下實體類保存到數據庫的就是SampleCharEnum對應的1、2、3
1 public virtual SampleCharEnum Type 2 { 3 get; 4 set; 5 } 6 7 public enum SampleCharEnum 8 { 9 On = 1, 10 Off = 2, 11 Dimmed = 3 12 }
生成sql日志配置
這個功能也是我比較喜歡Nhibernate的地方,因為Entity Framework依然沒有類似的功能,每次調試都需要用sql profiler來進行協助。
只需要繼承EmptyInterceptor類,並在Config里面配置一下就ok了。
1 public class SqlStatementInterceptor : EmptyInterceptor 2 { 3 public override NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql) 4 { 5 System.Diagnostics.Trace.WriteLine(sql.ToString()); 6 return sql; 7 } 8 }
1 public static FluentConfiguration GetConfiguration() 2 { 3 var model = AutoMap.Assembly(Assembly.Load("EntApp.ShinFlow.Data")). 4 Where(t => t.Namespace == "EntApp.ShinFlow.Data.Model") 5 .IgnoreBase<BaseEntity>() 6 .Conventions.AddFromAssemblyOf<EnumConvention>(); 7 8 return Fluently.Configure() 9 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 10 .Mappings(m=>{ 11 m.AutoMappings.Add(model); 12 m.FluentMappings.AddFromAssemblyOf<EntApp.ShinFlow.Data.CustomModel.User>(); 13 }) 14 .ExposeConfiguration(f=>f.SetInterceptor(new SqlStatementInterceptor())); 15 }
AutoMap時不允許Nhibernate自動生成Id
用EF時主鍵ID都是自己new的guid,在做主從表的時候很方便,但fluent nhibernate默認是自動給生成主鍵ID的,這里我們通過統一的配置來修改這一默認設置
1 public class AssignedIdConvention : IIdConvention 2 { 3 public void Apply(IIdentityInstance instance) 4 { 5 instance.GeneratedBy.Assigned(); 6 } 7 }
實現一個IConvention接口,告訴系統主鍵生成規則。這里主鍵生成規則Nhibernate內置有幾種,請自行google。
然后加到配置里面
1 public static FluentConfiguration GetConfiguration() 2 { 3 var model = AutoMap.Assembly(Assembly.Load("EntApp.ShineFlow.Data")). 4 Where(t => t.Namespace == "EntApp.ShineFlow.Data.Model") 5 .IgnoreBase<BaseEntity>() 6 .Conventions.AddFromAssemblyOf<EnumConvention>() 7 .Conventions.Add<AssignedIdConvention>() 8 .Conventions.Add < BinaryColumnLengthConvention>() 9 ; 10 11 return Fluently.Configure() 12 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 13 .Mappings(m=>{ 14 m.AutoMappings.Add(model); 15 m.FluentMappings.AddFromAssemblyOf<EntApp.ShineFlow.Data.CustomModel.User>(); 16 }) 17 18 .ExposeConfiguration(f=>f.SetInterceptor(new SqlStatementInterceptor())); 19 }
注意第7行。
AutoMap時配置Image字段長度
做附件上傳時,需要把附件存入數據庫的Image字段,相對應的實體類的類型為byte[],但nhibernate默認長度只能存8k,我們需要把限制改一下。
1 public class BinaryColumnLengthConvention : IPropertyConvention, IPropertyConventionAcceptance 2 { 3 public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) 4 { 5 criteria.Expect(x => x.Property.PropertyType == typeof(byte[])); 6 } 7 8 public void Apply(IPropertyInstance instance) 9 { 10 instance.Length(2147483647); 11 instance.CustomSqlType("varbinary(MAX)"); 12 } 13 }
這里我們通過繼承兩個接口,如果字段類型為byte[]時,把長度設置的最長。然后加入系統配置。
1 public static FluentConfiguration GetConfiguration() 2 { 3 var model = AutoMap.Assembly(Assembly.Load("EntApp.ShineFlow.Data")). 4 Where(t => t.Namespace == "EntApp.ShineFlow.Data.Model") 5 .IgnoreBase<BaseEntity>() 6 .Conventions.AddFromAssemblyOf<EnumConvention>() 7 .Conventions.Add<AssignedIdConvention>() 8 .Conventions.Add < BinaryColumnLengthConvention>() 9 ; 10 11 return Fluently.Configure() 12 .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString"))) 13 .Mappings(m=>{ 14 m.AutoMappings.Add(model); 15 m.FluentMappings.AddFromAssemblyOf<EntApp.ShineFlow.Data.CustomModel.User>(); 16 }) 17 18 .ExposeConfiguration(f=>f.SetInterceptor(new SqlStatementInterceptor())); 19 }
注意第8行
結尾:
從Entity framework的Code first剛出來時就非常關注,在項目中使用的也比較多,畢竟是微軟的親生兒子。但最近在剛剛使用Nhibernate時就發現了一些Entity所不具備的優點,比如枚舉的支持,sql日志的輸出,存儲過程的支持,sql的混用,xml 和automap的混用等等,明顯發現比entity framwork更靈活方便。
當然最新版的Entity Framework也增加了許多功能,但總體感覺還是太慢,希望EF加油吧!