NHibernateManager.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Data.Common;
  29. using System.Reflection;
  30. using log4net;
  31. using NHibernate;
  32. using NHibernate.Cfg;
  33. using NHibernate.Tool.hbm2ddl;
  34. using OpenMetaverse;
  35. using Environment=NHibernate.Cfg.Environment;
  36. namespace OpenSim.Data.NHibernate
  37. {
  38. public class NHibernateManager
  39. {
  40. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  41. private string dialect;
  42. private Configuration configuration;
  43. private ISessionFactory sessionFactory;
  44. #region Initialization
  45. /// <summary>
  46. /// Initiate NHibernate Manager
  47. /// </summary>
  48. /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param>
  49. /// <param name="store">Name of the store</param>
  50. public NHibernateManager(string connect, string store)
  51. {
  52. ParseConnectionString(connect);
  53. //To create sql file uncomment code below and write the name of the file
  54. //SchemaExport exp = new SchemaExport(cfg);
  55. //exp.SetOutputFile("nameofthefile.sql");
  56. //exp.Create(false, true);
  57. Assembly assembly = GetType().Assembly;
  58. sessionFactory = configuration.BuildSessionFactory();
  59. RunMigration(dialect, assembly, store);
  60. }
  61. /// <summary>
  62. /// Initiate NHibernate Manager with spesific assembly
  63. /// </summary>
  64. /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param>
  65. /// <param name="store">Name of the store</param>
  66. /// <param name="assembly">Outside assembly to be included </param>
  67. public NHibernateManager(string connect, string store, Assembly assembly)
  68. {
  69. ParseConnectionString(connect);
  70. configuration.AddAssembly(assembly);
  71. sessionFactory = configuration.BuildSessionFactory();
  72. RunMigration(dialect, assembly, store);
  73. }
  74. /// <summary>
  75. /// Parses the connection string and creates the NHibernate configuration
  76. /// </summary>
  77. /// <param name="connect">NHibernate dialect, driver and connection string separated by ';'</param>
  78. private void ParseConnectionString(string connect)
  79. {
  80. // Split out the dialect, driver, and connect string
  81. char[] split = { ';' };
  82. string[] parts = connect.Split(split, 3);
  83. if (parts.Length != 3)
  84. {
  85. // TODO: make this a real exception type
  86. throw new Exception("Malformed Inventory connection string '" + connect + "'");
  87. }
  88. dialect = parts[0];
  89. // NHibernate setup
  90. configuration = new Configuration();
  91. configuration.SetProperty(Environment.ConnectionProvider,
  92. "NHibernate.Connection.DriverConnectionProvider");
  93. configuration.SetProperty(Environment.Dialect,
  94. "NHibernate.Dialect." + dialect);
  95. configuration.SetProperty(Environment.ConnectionDriver,
  96. "NHibernate.Driver." + parts[1]);
  97. configuration.SetProperty(Environment.ConnectionString, parts[2]);
  98. configuration.AddAssembly("OpenSim.Data.NHibernate");
  99. }
  100. /// <summary>
  101. /// Runs migration for the the store in assembly
  102. /// </summary>
  103. /// <param name="dialect">Dialect in use</param>
  104. /// <param name="assembly">Assembly where migration files exist</param>
  105. /// <param name="store">Name of the store in use</param>
  106. private void RunMigration(string dialect, Assembly assembly, string store)
  107. {
  108. // Migration subtype is the folder name under which migrations are stored. For mysql this folder is
  109. // MySQLDialect instead of MySQL5Dialect which is the dialect currently in use. To avoid renaming
  110. // this folder each time the mysql version changes creating simple mapping:
  111. String migrationSubType = dialect;
  112. if (dialect.StartsWith("MySQL"))
  113. {
  114. migrationSubType = "MySQLDialect";
  115. }
  116. Migration migration = new Migration((DbConnection)sessionFactory.ConnectionProvider.GetConnection(), assembly, migrationSubType, store);
  117. migration.Update();
  118. }
  119. #endregion
  120. /// <summary>
  121. /// Gets object of given type from database with given id.
  122. /// Uses stateless session for efficiency.
  123. /// </summary>
  124. /// <param name="type">Type of the object.</param>
  125. /// <param name="id">Id of the object.</param>
  126. /// <returns>The object or null if object was not found.</returns>
  127. public object Get(Type type, Object id)
  128. {
  129. using (IStatelessSession session = sessionFactory.OpenStatelessSession())
  130. {
  131. object obj = null;
  132. try
  133. {
  134. obj = session.Get(type.FullName, id);
  135. }
  136. catch (Exception e)
  137. {
  138. m_log.ErrorFormat("[NHIBERNATE] {0} of id {1} loading threw exception: " + e.ToString(), type.Name, id);
  139. }
  140. return obj;
  141. }
  142. }
  143. /// <summary>
  144. /// Gets object of given type from database with given id.
  145. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient.
  146. /// </summary>
  147. /// <param name="type">Type of the object.</param>
  148. /// <param name="id">Id of the object.</param>
  149. /// <returns>The object or null if object was not found.</returns>
  150. public object GetWithStatefullSession(Type type, Object id)
  151. {
  152. using (ISession session = sessionFactory.OpenSession())
  153. {
  154. object obj = null;
  155. try
  156. {
  157. obj = session.Get(type.FullName, id);
  158. }
  159. catch (Exception e)
  160. {
  161. m_log.ErrorFormat("[NHIBERNATE] {0} of id {1} loading threw exception: " + e.ToString(), type.Name, id);
  162. }
  163. return obj;
  164. }
  165. }
  166. /// <summary>
  167. /// Inserts given object to database.
  168. /// Uses stateless session for efficiency.
  169. /// </summary>
  170. /// <param name="obj">Object to be insterted.</param>
  171. /// <returns>Identifier of the object. Useful for situations when NHibernate generates the identifier.</returns>
  172. public object Insert(object obj)
  173. {
  174. try
  175. {
  176. using (IStatelessSession session = sessionFactory.OpenStatelessSession())
  177. {
  178. using (ITransaction transaction=session.BeginTransaction())
  179. {
  180. Object identifier=session.Insert(obj);
  181. transaction.Commit();
  182. return identifier;
  183. }
  184. }
  185. }
  186. catch (Exception e)
  187. {
  188. m_log.Error("[NHIBERNATE] issue inserting object ", e);
  189. return null;
  190. }
  191. }
  192. /// <summary>
  193. /// Inserts given object to database.
  194. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient.
  195. /// </summary>
  196. /// <param name="obj">Object to be insterted.</param>
  197. /// <returns>Identifier of the object. Useful for situations when NHibernate generates the identifier.</returns>
  198. public object InsertWithStatefullSession(object obj)
  199. {
  200. try
  201. {
  202. using (ISession session = sessionFactory.OpenSession())
  203. {
  204. using (ITransaction transaction = session.BeginTransaction())
  205. {
  206. Object identifier = session.Save(obj);
  207. transaction.Commit();
  208. return identifier;
  209. }
  210. }
  211. }
  212. catch (Exception e)
  213. {
  214. m_log.Error("[NHIBERNATE] issue inserting object ", e);
  215. return null;
  216. }
  217. }
  218. /// <summary>
  219. /// Updates given object to database.
  220. /// Uses stateless session for efficiency.
  221. /// </summary>
  222. /// <param name="obj">Object to be updated.</param>
  223. /// <returns>True if operation was succesful.</returns>
  224. public bool Update(object obj)
  225. {
  226. try
  227. {
  228. using (IStatelessSession session = sessionFactory.OpenStatelessSession())
  229. {
  230. using (ITransaction transaction = session.BeginTransaction())
  231. {
  232. session.Update(obj);
  233. transaction.Commit();
  234. return true;
  235. }
  236. }
  237. }
  238. catch (Exception e)
  239. {
  240. m_log.Error("[NHIBERNATE] issue updating object ", e);
  241. return false;
  242. }
  243. }
  244. /// <summary>
  245. /// Updates given object to database.
  246. /// Use this method for objects containing collections. For flat objects stateless mode is more efficient.
  247. /// </summary>
  248. /// <param name="obj">Object to be updated.</param>
  249. /// <returns>True if operation was succesful.</returns>
  250. public bool UpdateWithStatefullSession(object obj)
  251. {
  252. try
  253. {
  254. using (ISession session = sessionFactory.OpenSession())
  255. {
  256. using (ITransaction transaction = session.BeginTransaction())
  257. {
  258. session.Update(obj);
  259. transaction.Commit();
  260. return true;
  261. }
  262. }
  263. }
  264. catch (Exception e)
  265. {
  266. m_log.Error("[NHIBERNATE] issue updating object ", e);
  267. return false;
  268. }
  269. }
  270. /// <summary>
  271. /// Deletes given object from database.
  272. /// </summary>
  273. /// <param name="obj">Object to be deleted.</param>
  274. /// <returns>True if operation was succesful.</returns>
  275. public bool Delete(object obj)
  276. {
  277. try
  278. {
  279. using (IStatelessSession session = sessionFactory.OpenStatelessSession())
  280. {
  281. using (ITransaction transaction = session.BeginTransaction())
  282. {
  283. session.Delete(obj);
  284. transaction.Commit();
  285. return true;
  286. }
  287. }
  288. }
  289. catch (Exception e)
  290. {
  291. m_log.Error("[NHIBERNATE] issue deleting object ", e);
  292. return false;
  293. }
  294. }
  295. /// <summary>
  296. /// Returns statefull session which can be used to execute custom nhibernate or sql queries.
  297. /// </summary>
  298. /// <returns>Statefull session</returns>
  299. public ISession GetSession()
  300. {
  301. return sessionFactory.OpenSession();
  302. }
  303. /// <summary>
  304. /// Drops the database schema. This exist for unit tests. It should not be invoked from other than test teardown.
  305. /// </summary>
  306. public void DropSchema()
  307. {
  308. SchemaExport export = new SchemaExport(this.configuration);
  309. export.Drop(true, true);
  310. using (ISession session = sessionFactory.OpenSession())
  311. {
  312. ISQLQuery sqlQuery = session.CreateSQLQuery("drop table migrations");
  313. sqlQuery.ExecuteUpdate();
  314. }
  315. }
  316. }
  317. }