NHiberante从.net framework转移到.net standard(.net core 2.2)时遇到的坑及填坑
Posted wangpengzong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NHiberante从.net framework转移到.net standard(.net core 2.2)时遇到的坑及填坑相关的知识,希望对你有一定的参考价值。
在.net framework中的创建session代码先贴一个
1 public class SessionBuilder 2 3 private static ISessionFactory _sessionFactory = null; 4 5 public SessionBuilder() 6 7 if (_sessionFactory == null) 8 9 //创建ISessionFactory 10 _sessionFactory = GetSessionFactory(); 11 12 13 14 /// <summary> 15 /// 创建ISessionFactory 16 /// </summary> 17 /// <returns></returns> 18 public static ISessionFactory GetSessionFactory() 19 20 //HibernatingRhinos.Profiler.Appender.NHibernate.NHibernateProfiler.Initialize(); 21 22 var mappers = new ModelMapper(); 23 mappers.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes()); 24 25 var cfg = new Configuration().Configure(); 26 cfg.AddDeserializedMapping(mappers.CompileMappingForAllExplicitlyAddedEntities(), ""); 27 28 return cfg.BuildSessionFactory(); 29 30 31 /// <summary> 32 /// 打开ISession 33 /// </summary> 34 /// <returns></returns> 35 public static ISession GetSession() 36 37 if (_sessionFactory == null || _sessionFactory.IsClosed) 38 39 //创建ISessionFactory 40 _sessionFactory = GetSessionFactory(); 41 42 43 44 45 #region 打开一个新的Session 46 public static ISession OpenSession() 47 48 return _sessionFactory.OpenSession(); 49 50 51 #endregion 52 53
与数据库的交互时,需要先在web.config配置(数据库为sql server)
<configuration> <configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" /> </configSections> <!--NHibernate配置开始--> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <session-factory> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property> <property name="show_sql">false</property> <property name="connection.connection_string_name">ylsdai</property> <property name="adonet.batch_size">30</property> <property name="generate_statistics">false</property> <property name="format_sql">true</property> <property name="command_timeout">60</property> <property name="current_session_context_class">web</property> <!--<property name="cache.provider_class">NHibernate.Caches.SysCache2.SysCacheProvider,NHibernate.Caches.SysCache2</property> <property name="cache.default_expiration">120</property> <property name="cache.use_second_level_cache">true</property> <property name="cache.use_query_cache">true</property>--> </session-factory> </hibernate-configuration> <!--NHibernate配置结束--> <connectionStrings> <!--test_db--> <!--<add name="ylsdai" connectionString="data source=0.0.0.1,111;database=test_db;uid=sa;pwd=123456" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
映射类
using NHibernate.Mapping.ByCode; using NHibernate.Mapping.ByCode.Conformist; namespace ClassMapping #region CityMap public class CityMap : ClassMapping<City> public CityMap() SelectBeforeUpdate(true); DynamicUpdate(true); //Cache(p => p.Usage(CacheUsage.ReadWrite)); Id(p => p.CityId, map => map.Generator(Generators.Native)); Property(p => p.OldCityId); Property(p => p.ParentId); Property(p => p.CityName); Property(p => p.EnCityName); Property(p => p.CityImgUrl); Property(p => p.LatLng); Property(p => p.Keywords); Property(p => p.IsRecommend); Property(p => p.IsDepart); Property(p => p.AreaId); Property(p => p.CityContent); #endregion
将实体写好,就可以进行实现了
但是在迁移到.net core的时候遇到的问题:
1. 创建Session,使用.net framework的方法将不可用
2.config中对于NHiberante的配置也读取不到
3.基于问题1,映射类也无法进行实现
好在是在.net core中有一个辅助的开源框架Fluent NHibernate,它可以帮我解决上面遇到的问题,但是在具体使用时也踩了不少坑
1.网上的文档基本都是映射类在xml中的,但是当实际项目在.cs文件中时,大量的文件映射从.cs文件迁到到.xml文件将变得特别繁琐
最后的解决办法,创建session方法中GetSessionFactory方法做以下修改
/// <summary> /// 创建ISessionFactory /// </summary> /// <returns></returns> public static ISessionFactory GetSessionFactory() var assemblyName = Assembly.Load("ClassMapping"); NHibernate.Cfg.Configuration setCfg(NHibernate.Cfg.Configuration c) c.Properties.Add("show_sql", "true"); c.Properties.Add("adonet.batch_size", "1000"); c.Properties.Add("generate_statistics", "false"); c.Properties.Add("format_sql", "true"); c.Properties.Add("command_timeout", "60"); c.Properties.Add("current_session_context_class", "web"); return c; return Fluently.Configure().Database( FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2012.ConnectionString("Server=0.0.0.1,111;Database=test_db;Uid=sa;Pwd=123456;")) .Mappings(m => m.FluentMappings.AddFromAssembly(assemblyName)) .ExposeConfiguration(c => new SchemaUpdate(c).Execute(true, false)) .ExposeConfiguration(c => setCfg(c)) //.ExposeConfiguration(f => f.SetInterceptor(new SqlStatementInterceptor())) .BuildSessionFactory();
其中映射类的引入在
.Mappings(m => m.FluentMappings.AddFromAssembly(assemblyName))
这句话,是将命名空间引入,所以具体映射类可以重新新建一个项目,名字就叫做ClassMapping,具体的映射类做以下修改
1 using Entity; 2 using FluentNHibernate.Mapping; 3 4 namespace ClassMapping 5 6 #region CityMap 7 public class CityMap : ClassMap<City> 8 9 public CityMap() 10 11 Table("City"); 12 13 //SelectBeforeUpdate(true); 14 //DynamicUpdate(true); 15 //Cache(p => p.Usage(CacheUsage.ReadWrite)); 16 Id(p => p.CityId); 17 Map(p => p.OldCityId); 18 Map(p => p.ParentId); 19 Map(p => p.CityName); 20 Map(p => p.EnCityName); 21 Map(p => p.CityImgUrl); 22 Map(p => p.LatLng); 23 Map(p => p.Keywords); 24 Map(p => p.IsRecommend); 25 Map(p => p.IsDepart); 26 Map(p => p.AreaId); 27 Map(p => p.CityContent); 28 29 30 #endregion 31 32
在迁移过程中会碰到映射关系的迁移
以前的版本中为
OneToOne(p => p.City, map => map.Cascade(Cascade.All); map.Lazy(LazyRelation.Proxy); );//一对一 ManyToOne(p => p.Province, map => map.Column("ProvinceId"));//多对一 Bag(p => p.Counties, map => map.Key(k => k.Column("CountyId")); map.OrderBy(k => k.SortId); , rel => rel.OneToMany());//一对多
.net core版本中对应为
HasOne(p => p.City).Cascade.All().LazyLoad();//一对一 //References<Province>(r => r.Province).Column("ProvinceId").ForeignKey("ProvinceId").Cascade.None();//多对一,在实际运用中会出现问题 HasMany(p => p.Counties).KeyColumn("CountyId").OrderBy("CountyId").LazyLoad();//一对多
city实体
1 [Serializable] 2 public class City : BaseEntity 3 4 /// <summary> 5 /// CityId 6 /// </summary> 7 public virtual int CityId get; set; 8 9 /// <summary> 10 /// Version 11 /// </summary> 12 public virtual int Version get; set; 13 14 /// <summary> 15 /// OldCityId 16 /// </summary> 17 public virtual int OldCityId get; set; 18 19 /// <summary> 20 /// ParentId 21 /// </summary> 22 public virtual int ParentId get; set; 23 24 /// <summary> 25 /// 城市名称 26 /// </summary> 27 public virtual string CityName get; set; 28 29 /// <summary> 30 /// 城市英文名称 31 /// </summary> 32 public virtual string EnCityName get; set; 33 34 /// <summary> 35 /// CityImgUrl 36 /// </summary> 37 public virtual string CityImgUrl get; set; 38 39 /// <summary> 40 /// 经纬度 41 /// </summary> 42 public virtual string LatLng get; set; 43 44 /// <summary> 45 /// 关键字 46 /// </summary> 47 public virtual string Keywords get; set; 48 49 /// <summary> 50 /// 是否推荐 51 /// </summary> 52 public virtual bool IsRecommend get; set; 53 54 /// <summary> 55 /// IsDepart 56 /// </summary> 57 public virtual bool IsDepart get; set; 58 59 /// <summary> 60 /// 航区 61 /// </summary> 62 public virtual int AreaId get; set; 63 64 /// <summary> 65 /// 城市介绍 66 /// </summary> 67 public virtual string CityContent get; set; 68 69
下面是操作session,进行数据库调用的方法
1 /// <summary> 2 /// Hibernate操作Helper 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 public class DbHelper<T> where T : BaseEntity 6 7 private readonly ISession _session = SessionBuilder.GetSession(); 8 //protected static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 9 10 public DbHelper() 11 12 public DbHelper(ISession session) 13 14 _session = session; 15 16 17 #region 获取一个实体 18 /// <summary> 19 /// 获取一个实体(一级缓存) 20 /// </summary> 21 /// <param name="id"></param> 22 /// <returns></returns> 23 public T Load(int id) 24 25 return _session.Load<T>(id); 26 27 28 #endregion 29 30 #region 获取一个实体(缓存) 31 /// <summary> 32 /// 获取一个实体(二级缓存) 33 /// </summary> 34 /// <param name="id"></param> 35 /// <returns></returns> 36 public T Get(int id) 37 38 return _session.Get<T>(id); 39 40 #endregion 41 42 #region 销毁一个实体 43 /// <summary> 44 /// 销毁一个实体 45 /// </summary> 46 /// <param name="obj"></param> 47 /// <returns></returns> 48 public void Evict(object obj) 49 50 _session.Evict(obj); 51 52 #endregion 53 54 /// <summary> 55 /// 根据SQL语句获取 56 /// </summary> 57 /// <param name="sql"></param> 58 public ISQLQuery CreateSqlQuery(string sql) 59 60 return _session.CreateSQLQuery(sql); 61 62 63 /// <summary> 64 /// 获取集合 65 /// </summary> 66 /// <param name="hql"></param> 67 /// <returns></returns> 68 public ICriteria GetCriteria(string hql) 69 70 return _session.CreateCriteria(hql); 71 72 73 #region 获取全部数据 74 /// <summary> 75 /// 获取全部数据 76 /// </summary> 77 /// <param name="cacheable">是否缓存</param> 78 /// <returns></returns> 79 public IEnumerable<T> GetAll(bool cacheable) 80 81 var ic = _session.CreateCriteria(typeof(T)); 82 IEnumerable<T> list = ic.SetCacheable(cacheable).List<T>() ?? new List<T>(); 83 return list; 84 85 #endregion 86 87 #region 插入或者更新数据 88 /// <summary> 89 /// 插入数据 90 /// </summary> 91 /// <param name="entity"></param> 92 /// <returns></returns> 93 public int Save(T entity) 94 95 var id = 0; 96 var session = this._session; 97 ITransaction tan = session.BeginTransaction(); 98 99 try 100 101 entity = session.Merge(entity); 102 103 catch (Exception e) 104 105 //Log.DebugFormat($"Save124,Exception:e.Message,entity:JsonConvert.SerializeObject(entity)"); 106 107 108 try 109 110 tan.Begin(); 111 id = (int)session.Save(entity); 112 session.Flush(); 113 tan.Commit(); 114 115 catch (Exception e) 116 117 //Log.DebugFormat($"Save136,Exception:e.Message,entity:JsonConvert.SerializeObject(entity)"); 118 tan.Rollback(); 119 throw; 120 121 122 return id; 123 124 #endregion 125 126 #region 更新数据 127 /// <summary> 128 /// 更新数据 129 /// </summary> 130 /// <param name="entity"></param> 131 /// <returns></returns> 132 public int Update(T entity) 133 134 int result = 0; 135 ITransaction tan = _session.BeginTransaction(); 136 var session = this._session; 137 //entity = (T)_session.Merge(entity); 138 try 139 140 entity = session.Merge(entity); 141 142 catch (Exception e) 143 144 //Log.DebugFormat($"Update163,Exception:e.Message,entity:JsonConvert.SerializeObject(entity)"); 145 146 try 147 148 tan.Begin(); 149 _session.Update(entity); 150 _session.Flush(); 151 tan.Commit(); 152 result++; 153 154 catch (Exception e) 155 156 //Log.DebugFormat($"Update175,Exception:e.Message,entity:JsonConvert.SerializeObject(entity)"); 157 tan.Rollback(); 158 throw; 159 160 return result; 161 162 #endregion 163 164 #region 删除一条数据 165 /// <summary> 166 /// 删除一条数据 167 /// </summary> 168 /// <param name="id"></param> 169 /// <returns></returns> 170 public int DeleteModelById(int id) 171 172 int result = 0; 173 object item = Get(id); 174 //ITransaction tan = _session.BeginTransaction(); 175 try 176 177 //tan.Begin(); 178 _session.Delete(item); 179 _session.Flush(); 180 //tan.Commit(); 181 result++; 182 183 catch (Exception) 184 185 //tan.Rollback(); 186 throw; 187 188 189 return result; 190 191 #endregion 192 193 #region 删除一个实体对象 194 /// <summary> 195 /// 删除一个实体对象 196 /// </summary> 197 /// <param name="entity"></param> 198 /// <returns></returns> 199 public int DeleteModel(BaseEntity entity) 200 201 var result = 0; 202 //ITransaction tan = _session.BeginTransaction(); 203 try 204 205 //tan.Begin(); 206 _session.Delete(entity); 207 _session.Flush(); 208 //tan.Commit(); 209 result++; 210 211 catch (Exception) 212 213 //tan.Rollback(); 214 throw; 215 216 return result; 217 218 #endregion 219 220 /// <summary> 221 /// 根据SQL语句删除 222 /// </summary> 223 /// <param name="sql"></param> 224 public void DeleteList(string sql) 225 226 _session.CreateSQLQuery(sql).UniqueResult(); 227 228 229 /// <summary> 230 /// 删除泛型集合 231 /// </summary> 232 /// <param name="models"></param> 233 public void DeleteList(IList<T> models) 234 235 foreach (var model in models) 236 237 DeleteModel(model); 238 239 240 241 public bool IsExist(Expression<Func<T, bool>> keyWhere) 242 243 var ss = _session.QueryOver<T>().Where(keyWhere); 244 return ss.RowCount() > 0; 245 246 247 #region GetQuery 248 /// <summary> 249 /// GetQuery 250 /// </summary> 251 /// <returns></returns> 252 public IQueryable<T> GetQuery() 253 254 try 255 256 return _session.Query<T>(); 257 258 catch (Exception e) 259 260 var session = SessionBuilder.GetSession(); 261 return session.Query<T>(); 262 263 264 #endregion 265 266 #region GetQueryOver 267 /// <summary> 268 /// GetQueryOver 269 /// </summary> 270 /// <returns></returns> 271 public IQueryOver<T, T> GetQueryOver(Expression<Func<T, bool>> keyWhere) 272 273 return _session.QueryOver<T>().Where(keyWhere); 274 275 276 #endregion 277 278 #region GetQueryOver 279 /// <summary> 280 /// GetQueryOver 281 /// </summary> 282 /// <returns></returns> 283 public IQueryOver<T, T> GetQueryOver() 284 285 return _session.QueryOver<T>(); 286 287 #endregion 288 289 #region 获取集合ByHql 290 /// <summary> 291 /// 获取集合ByHql 292 /// </summary> 293 /// <param name="strHql"></param> 294 /// <returns></returns> 295 public IQuery GetQueryByHql(string strHql) 296 297 return _session.CreateQuery(strHql); 298 299 #endregion 300 301 #region 获取集合BySql 302 /// <summary> 303 /// 获取集合BySql 304 /// </summary> 305 /// <param name="strSql"></param> 306 /// <returns></returns> 307 public IQuery GetQueryBySql(string strSql) 308 309 return _session.CreateSQLQuery(strSql); 310 311 #endregion 312
以上是关于NHiberante从.net framework转移到.net standard(.net core 2.2)时遇到的坑及填坑的主要内容,如果未能解决你的问题,请参考以下文章
从 .NET Core 调用 Web API 到 .NET Framework
从 .NET Framework 4.6 迁移到 .NET5 后,API 帖子正文为空
从哪里开始 .NET Entity Framework 和 ORM?
.NET Frameworks 从 3.5 到 2.0 的向前兼容性