DataConnectionBase.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Data.Common;
  6. using System.Drawing.Design;
  7. using FastReport.Data.JsonConnection;
  8. using FastReport.Utils;
  9. namespace FastReport.Data
  10. {
  11. /// <summary>
  12. /// The base class for all data connection components such as <see cref="MsSqlDataConnection"/>.
  13. /// </summary>
  14. /// <example>This example shows how to add a new MS Access connection to the report.
  15. /// <code>
  16. /// Report report1;
  17. /// MsAccessDataConnection conn = new MsAccessDataConnection();
  18. /// conn.DataSource = @"c:\data.mdb";
  19. /// report1.Dictionary.Connections.Add(conn);
  20. /// conn.CreateAllTables();
  21. /// </code>
  22. /// </example>
  23. public abstract partial class DataConnectionBase : DataComponentBase, IParent
  24. {
  25. #region Fields
  26. private DataSet dataSet;
  27. private TableCollection tables;
  28. private bool isSqlBased;
  29. private string connectionString;
  30. private string connectionStringExpression;
  31. private bool loginPrompt;
  32. private int commandTimeout;
  33. private string lastConnectionString;
  34. #endregion
  35. #region Properties
  36. /// <summary>
  37. /// Gets an internal <b>DataSet</b> object that contains all data tables.
  38. /// </summary>
  39. [Browsable(false)]
  40. public DataSet DataSet
  41. {
  42. get
  43. {
  44. if (dataSet == null)
  45. dataSet = CreateDataSet();
  46. return dataSet;
  47. }
  48. }
  49. /// <summary>
  50. /// Gets a collection of data tables in this connection.
  51. /// </summary>
  52. /// <remarks>
  53. /// To add a table to the connection, you must either create a new TableDataSource and add it
  54. /// to this collection or call the <see cref="CreateAllTables()"/> method which will add
  55. /// all tables available in the database.
  56. /// </remarks>
  57. [Browsable(false)]
  58. public TableCollection Tables
  59. {
  60. get { return tables; }
  61. }
  62. /// <summary>
  63. /// Gets or sets a connection string that contains all connection parameters.
  64. /// </summary>
  65. /// <remarks>
  66. /// <para>To modify some parameter of the connection, use respective
  67. /// <b>ConnectionStringBuilder</b> class.</para>
  68. /// <para><b>Security note:</b> the connection string may contain a user name/password.
  69. /// This information is stored in a report file. By default, it is crypted using the standard
  70. /// FastReport's password. Since FastReport's source code is available to anyone who paid for it,
  71. /// it may be insecure to use the standard password. For more security, you should use own
  72. /// password. To do this, specify it in the <b>Crypter.DefaultPassword</b> property.</para>
  73. /// </remarks>
  74. /// <example>This example demonstrates how to change a connection string:
  75. /// <code>
  76. /// OleDbConnectionStringBuilder builder = new OleDbConnectionStringBuilder(oleDbConnection1.ConnectionString);
  77. /// builder.PersistSecurityInfo = false;
  78. /// oleDbConnection1.ConnectionString = builder.ToString();
  79. /// </code>
  80. /// </example>
  81. [Category("Data")]
  82. public string ConnectionString
  83. {
  84. get
  85. {
  86. if (Report != null && Report.IsRunning && !String.IsNullOrEmpty(ConnectionStringExpression))
  87. return Report.Calc(ConnectionStringExpression).ToString();
  88. return connectionString;
  89. }
  90. set { SetConnectionString(Crypter.DecryptString(value)); }
  91. }
  92. /// <summary>
  93. /// Gets or sets an expression that returns a connection string.
  94. /// </summary>
  95. /// <remarks>
  96. /// Use this property to set the connection string dynamically.
  97. /// <para/>The recommended way to do this is to define a report parameter. You can do this in the
  98. /// "Data" window. Once you have defined the parameter, you can use it to pass a value
  99. /// to the connection. Set the <b>ConnectionStringExpression</b> property of the
  100. /// connection object to the report parameter's name (so it will look like [myReportParam]).
  101. /// To pass a value to the report parameter from your application, use the
  102. /// <see cref="Report.SetParameterValue"/> method.
  103. /// <note type="caution">
  104. /// Once you set value for this property, the <see cref="ConnectionString"/> property will be ignored
  105. /// when report is run.
  106. /// </note>
  107. /// </remarks>
  108. [Category("Data")]
  109. [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))]
  110. public string ConnectionStringExpression
  111. {
  112. get
  113. {
  114. return connectionStringExpression;
  115. }
  116. set { connectionStringExpression = value; }
  117. }
  118. /// <summary>
  119. /// Gets or sets a value indicates if this connection is SQL-based.
  120. /// </summary>
  121. [Browsable(false)]
  122. public bool IsSqlBased
  123. {
  124. get { return isSqlBased; }
  125. set { isSqlBased = value; }
  126. }
  127. /// <summary>
  128. /// Gets or sets a value indicating whether a login dialog appears immediately before opening a connection.
  129. /// </summary>
  130. /// <remarks>
  131. /// Set <b>LoginPrompt</b> to <b>true</b> to provide login dialog when establishing a connection. If this
  132. /// property is <b>false</b> (by default), you should provide login information (user name and password)
  133. /// in the <see cref="ConnectionString"/> property. Though that property is stored in a crypted form,
  134. /// this may be insecure.
  135. /// <para/>Another way to pass login information to the connection is to use
  136. /// <see cref="ConnectionStringExpression"/> property that is bound to the report parameter. In that
  137. /// case you supply the entire connection string from your application.
  138. /// </remarks>
  139. [Category("Data")]
  140. [DefaultValue(false)]
  141. public bool LoginPrompt
  142. {
  143. get { return loginPrompt; }
  144. set { loginPrompt = value; }
  145. }
  146. /// <summary>
  147. /// Gets or sets the command timeout, in seconds.
  148. /// </summary>
  149. [Category("Data")]
  150. [DefaultValue(30)]
  151. public int CommandTimeout
  152. {
  153. get { return commandTimeout; }
  154. set { commandTimeout = value; }
  155. }
  156. #endregion
  157. #region Private Methods
  158. private void GetDBObjectNames(string name, List<string> list)
  159. {
  160. DataTable schema = null;
  161. DbConnection conn = GetConnection();
  162. try
  163. {
  164. OpenConnection(conn);
  165. schema = conn.GetSchema("Tables", new string[] { null, null, null, name });
  166. }
  167. finally
  168. {
  169. DisposeConnection(conn);
  170. }
  171. foreach (DataRow row in schema.Rows)
  172. {
  173. list.Add(row["TABLE_NAME"].ToString());
  174. }
  175. }
  176. private string PrepareSelectCommand(string selectCommand, string tableName, DbConnection connection)
  177. {
  178. if (String.IsNullOrEmpty(selectCommand))
  179. {
  180. selectCommand = "select * from " + QuoteIdentifier(tableName, connection);
  181. }
  182. return selectCommand;
  183. }
  184. private TableDataSource FindTableDataSource(DataTable table)
  185. {
  186. foreach (TableDataSource c in Tables)
  187. {
  188. if (c.Table == table)
  189. return c;
  190. }
  191. return null;
  192. }
  193. #endregion
  194. #region Protected Methods
  195. /// <inheritdoc/>
  196. protected override void Dispose(bool disposing)
  197. {
  198. base.Dispose(disposing);
  199. if (disposing)
  200. DisposeDataSet();
  201. }
  202. /// <summary>
  203. /// Initializes a <b>DataSet</b> instance.
  204. /// </summary>
  205. /// <returns>The <b>DataSet</b> object.</returns>
  206. /// <remarks>
  207. /// This method is used to support FastReport infrastructure. You don't need to use it.
  208. /// </remarks>
  209. protected virtual DataSet CreateDataSet()
  210. {
  211. DataSet dataSet = new DataSet();
  212. dataSet.EnforceConstraints = false;
  213. return dataSet;
  214. }
  215. /// <summary>
  216. /// Disposes a <b>DataSet</b>.
  217. /// </summary>
  218. /// <remarks>
  219. /// This method is used to support FastReport infrastructure. You don't need to use it.
  220. /// </remarks>
  221. protected void DisposeDataSet()
  222. {
  223. if (dataSet != null)
  224. dataSet.Dispose();
  225. dataSet = null;
  226. }
  227. /// <summary>
  228. /// Sets the connection string.
  229. /// </summary>
  230. /// <param name="value">New connection string.</param>
  231. /// <remarks>
  232. /// Use this method if you need to perform some actions when the connection string is set.
  233. /// </remarks>
  234. protected virtual void SetConnectionString(string value)
  235. {
  236. connectionString = value;
  237. }
  238. /// <summary>
  239. /// Gets a connection string that contains username and password specified.
  240. /// </summary>
  241. /// <param name="userName">User name.</param>
  242. /// <param name="password">Password.</param>
  243. /// <remarks>
  244. /// Override this method to pass login information to the connection. Typical implementation
  245. /// must get the existing <see cref="ConnectionString"/>, merge specified login information into it
  246. /// and return the new value.
  247. /// </remarks>
  248. protected virtual string GetConnectionStringWithLoginInfo(string userName, string password)
  249. {
  250. return ConnectionString;
  251. }
  252. #endregion
  253. #region IParent Members
  254. /// <inheritdoc/>
  255. public bool CanContain(Base child)
  256. {
  257. return child is TableDataSource;
  258. }
  259. /// <inheritdoc/>
  260. public void GetChildObjects(ObjectCollection list)
  261. {
  262. foreach (TableDataSource c in Tables)
  263. {
  264. list.Add(c);
  265. }
  266. }
  267. /// <inheritdoc/>
  268. public void AddChild(Base child)
  269. {
  270. Tables.Add(child as TableDataSource);
  271. }
  272. /// <inheritdoc/>
  273. public void RemoveChild(Base child)
  274. {
  275. Tables.Remove(child as TableDataSource);
  276. }
  277. /// <inheritdoc/>
  278. public int GetChildOrder(Base child)
  279. {
  280. // we don't need to handle database objects' order.
  281. return 0;
  282. }
  283. /// <inheritdoc/>
  284. public void SetChildOrder(Base child, int order)
  285. {
  286. // do nothing
  287. }
  288. /// <inheritdoc/>
  289. public void UpdateLayout(float dx, float dy)
  290. {
  291. // do nothing
  292. }
  293. #endregion
  294. #region Public Methods
  295. /// <summary>
  296. /// Fills the <see cref="Tables"/> collection with all tables available in the database.
  297. /// </summary>
  298. /// <remarks>
  299. /// This method does not read the table data; to do this, call the
  300. /// <see cref="TableDataSource.LoadData"/> method of each table.
  301. /// </remarks>
  302. public void CreateAllTables()
  303. {
  304. CreateAllTables(true);
  305. }
  306. /// <summary>
  307. /// Fills the <see cref="Tables"/> collection with all tables available in the database.
  308. /// </summary>
  309. /// <param name="initSchema">Set to <b>true</b> to initialize each table's schema.</param>
  310. public virtual void CreateAllTables(bool initSchema)
  311. {
  312. List<string> tableNames = new List<string>();
  313. tableNames.AddRange(GetTableNames());
  314. FilterTables(tableNames);
  315. // remove tables with tablename that does not exist in the connection.
  316. for (int i = 0; i < Tables.Count; i++)
  317. {
  318. TableDataSource table = Tables[i];
  319. bool found = !String.IsNullOrEmpty(table.SelectCommand);
  320. // skip tables with non-empty selectcommand
  321. if (!found)
  322. {
  323. foreach (string tableName in tableNames)
  324. {
  325. if (String.Compare(table.TableName, tableName, true) == 0)
  326. {
  327. found = true;
  328. break;
  329. }
  330. }
  331. }
  332. // table name not found between actual tablenames. It may happen if we have edited the connection.
  333. if (!found)
  334. {
  335. table.Dispose();
  336. i--;
  337. }
  338. }
  339. // now create tables that are not created yet.
  340. foreach (string tableName in tableNames)
  341. {
  342. bool found = false;
  343. foreach (TableDataSource table in Tables)
  344. {
  345. if (String.Compare(table.TableName, tableName, true) == 0)
  346. {
  347. found = true;
  348. break;
  349. }
  350. }
  351. if (!found)
  352. {
  353. TableDataSource table = new TableDataSource();
  354. string fixedTableName = tableName.Replace(".", "_").Replace("[", "").Replace("]", "").Replace("\"", "");
  355. if (Report != null)
  356. {
  357. table.Name = Report.Dictionary.CreateUniqueName(fixedTableName);
  358. table.Alias = Report.Dictionary.CreateUniqueAlias(table.Alias);
  359. }
  360. else
  361. table.Name = fixedTableName;
  362. table.TableName = tableName;
  363. table.Connection = this;
  364. table.Enabled = false;
  365. Tables.Add(table);
  366. }
  367. }
  368. // init table schema
  369. if (initSchema)
  370. {
  371. foreach (TableDataSource table in Tables)
  372. {
  373. table.InitSchema();
  374. }
  375. }
  376. }
  377. /// <summary>
  378. /// Creates the relations between tables. Applies to XmlDataConnection only.
  379. /// </summary>
  380. public virtual void CreateRelations()
  381. {
  382. if (Report != null)
  383. {
  384. foreach (DataRelation relation in DataSet.Relations)
  385. {
  386. Relation rel = new Relation();
  387. rel.Name = relation.RelationName;
  388. rel.ParentDataSource = FindTableDataSource(relation.ParentTable);
  389. rel.ChildDataSource = FindTableDataSource(relation.ChildTable);
  390. string[] parentColumns = new string[relation.ParentColumns.Length];
  391. string[] childColumns = new string[relation.ChildColumns.Length];
  392. for (int i = 0; i < relation.ParentColumns.Length; i++)
  393. {
  394. parentColumns[i] = relation.ParentColumns[i].Caption;
  395. }
  396. for (int i = 0; i < relation.ChildColumns.Length; i++)
  397. {
  398. childColumns[i] = relation.ChildColumns[i].Caption;
  399. }
  400. rel.ParentColumns = parentColumns;
  401. rel.ChildColumns = childColumns;
  402. if (Report.Dictionary.Relations.FindEqual(rel) == null)
  403. Report.Dictionary.Relations.Add(rel);
  404. else
  405. rel.Dispose();
  406. }
  407. }
  408. }
  409. /// <summary>
  410. /// Gets an array of table names available in the database.
  411. /// </summary>
  412. /// <returns>An array of strings.</returns>
  413. public virtual string[] GetTableNames()
  414. {
  415. List<string> list = new List<string>();
  416. GetDBObjectNames("TABLE", list);
  417. GetDBObjectNames("VIEW", list);
  418. return list.ToArray();
  419. }
  420. /// <summary>
  421. /// Returns a type of connection.
  422. /// </summary>
  423. /// <returns><b>Type</b> instance.</returns>
  424. /// <remarks>
  425. /// You should override this method if you developing a new connection component.
  426. /// <para/>If your connection component does not use data connection, you need to override
  427. /// the <see cref="FillTableSchema"/> and <see cref="FillTableData"/> methods instead.
  428. /// </remarks>
  429. /// <example>Here is the example of this method implementation:
  430. /// <code>
  431. /// public override Type GetConnectionType()
  432. /// {
  433. /// return typeof(OleDbConnection);
  434. /// }
  435. /// </code>
  436. /// </example>
  437. public virtual Type GetConnectionType()
  438. {
  439. return null;
  440. }
  441. /// <summary>
  442. /// Returns a connection object.
  443. /// </summary>
  444. /// <returns>The <b>DbConnection</b> instance.</returns>
  445. /// <remarks>Either creates a new <b>DbConnection</b> instance of type provided by the
  446. /// <see cref="GetConnectionType"/> method, or returns the application connection if set
  447. /// in the Config.DesignerSettings.ApplicationConnection.</remarks>
  448. public DbConnection GetConnection()
  449. {
  450. Type connectionType = GetConnectionType();
  451. if (connectionType != null)
  452. {
  453. DbConnection connection = GetDefaultConnection();
  454. if (connection != null)
  455. return connection;
  456. // create a new connection object
  457. connection = Activator.CreateInstance(connectionType) as DbConnection;
  458. connection.ConnectionString = ConnectionString;
  459. return connection;
  460. }
  461. return null;
  462. }
  463. /// <summary>
  464. /// Opens a specified connection object.
  465. /// </summary>
  466. /// <param name="connection">Connection to open.</param>
  467. /// <remarks>
  468. /// Use this method to open a connection returned by the <see cref="GetConnection"/> method.
  469. /// <para/>This method displays a login dialog if your connection has the <see cref="LoginPrompt"/>
  470. /// property set to <b>true</b>. Once you have entered an user name and password in
  471. /// this dialog, it will remeber the entered values and will not used anymore in this report session.
  472. /// </remarks>
  473. public void OpenConnection(DbConnection connection)
  474. {
  475. if (connection.State == ConnectionState.Open)
  476. return;
  477. if (!String.IsNullOrEmpty(lastConnectionString))
  478. {
  479. // connection string is already provided, use it and skip other logic.
  480. connection.ConnectionString = lastConnectionString;
  481. }
  482. else
  483. {
  484. // try the global DatabaseLogin event
  485. string oldConnectionString = ConnectionString;
  486. DatabaseLoginEventArgs e = new DatabaseLoginEventArgs(ConnectionString);
  487. Config.ReportSettings.OnDatabaseLogin(this, e);
  488. // that event may do the following:
  489. // - modify the ConnectionString
  490. // - modify the username/password
  491. // - there is no event handler attached to the event, so it does nothing.
  492. if (oldConnectionString != e.ConnectionString)
  493. {
  494. // the connection string was modified. Set the FLastConnectionString to use it next time silently.
  495. lastConnectionString = e.ConnectionString;
  496. }
  497. else
  498. {
  499. if (!String.IsNullOrEmpty(e.UserName) || !String.IsNullOrEmpty(e.Password))
  500. {
  501. // the username/password was modified. Get new connection string
  502. lastConnectionString = GetConnectionStringWithLoginInfo(e.UserName, e.Password);
  503. }
  504. else if (LoginPrompt)
  505. {
  506. ShowLoginForm(lastConnectionString);
  507. }
  508. }
  509. // update the connection if it's not done yet
  510. if (!String.IsNullOrEmpty(lastConnectionString))
  511. connection.ConnectionString = lastConnectionString;
  512. }
  513. connection.Open();
  514. Config.ReportSettings.OnAfterDatabaseLogin(this, new AfterDatabaseLoginEventArgs(connection));
  515. }
  516. /// <summary>
  517. /// Disposes a connection.
  518. /// </summary>
  519. /// <param name="connection">The connection to dispose.</param>
  520. public void DisposeConnection(DbConnection connection)
  521. {
  522. if (ShouldNotDispose(connection))
  523. return;
  524. if (connection != null)
  525. connection.Dispose();
  526. }
  527. /// <summary>
  528. /// Returns a <see cref="DbDataAdapter"/> object that is specific to this connection.
  529. /// </summary>
  530. /// <param name="selectCommand">The SQL command used to fetch a table data rows.</param>
  531. /// <param name="connection">The connection object.</param>
  532. /// <param name="parameters">The select command parameters.</param>
  533. /// <returns>The <b>DbDataAdapter</b> object.</returns>
  534. /// <remarks>
  535. /// You should override this method if you are developing a new connection component. In this method,
  536. /// you need to create the adapter and set its <b>SelectCommand</b>'s parameters.
  537. /// <para/>If your connection does not use data adapter, you need to override
  538. /// the <see cref="FillTableSchema"/> and <see cref="FillTableData"/> methods instead.
  539. /// </remarks>
  540. /// <example>Here is the example of this method implementation:
  541. /// <code>
  542. /// public override DbDataAdapter GetAdapter(string selectCommand, DbConnection connection,
  543. /// CommandParameterCollection parameters)
  544. /// {
  545. /// OleDbDataAdapter adapter = new OleDbDataAdapter(selectCommand, connection as OleDbConnection);
  546. /// foreach (CommandParameter p in parameters)
  547. /// {
  548. /// OleDbParameter parameter = adapter.SelectCommand.Parameters.Add(p.Name, (OleDbType)p.DataType, p.Size);
  549. /// parameter.Value = p.Value;
  550. /// }
  551. /// return adapter;
  552. /// }
  553. /// </code>
  554. /// </example>
  555. public virtual DbDataAdapter GetAdapter(string selectCommand, DbConnection connection,
  556. CommandParameterCollection parameters)
  557. {
  558. return null;
  559. }
  560. /// <summary>
  561. /// Gets the type of parameter that is specific to this connection.
  562. /// </summary>
  563. /// <returns>The parameter's type.</returns>
  564. /// <remarks>
  565. /// This property is used in the report designer to display available data types when you edit the
  566. /// connection parameters. For example, the type of OleDbConnection parameter is a <b>OleDbType</b>.
  567. /// </remarks>
  568. public virtual Type GetParameterType()
  569. {
  570. return null;
  571. }
  572. /// <summary>
  573. /// Quotes the specified DB identifier such as table name or column name.
  574. /// </summary>
  575. /// <param name="value">Identifier to quote.</param>
  576. /// <param name="connection">The opened DB connection.</param>
  577. /// <returns>The quoted identifier.</returns>
  578. public abstract string QuoteIdentifier(string value, DbConnection connection);
  579. /// <summary>
  580. /// Fills the table schema.
  581. /// </summary>
  582. /// <param name="table">DataTable to fill.</param>
  583. /// <param name="selectCommand">The SQL select command.</param>
  584. /// <param name="parameters">SQL parameters.</param>
  585. /// <remarks>
  586. /// Usually you don't need to use this method. Internally it uses the <see cref="GetConnection"/> and
  587. /// <see cref="GetAdapter"/> methods to fill the table schema. If you create own connection component
  588. /// that does not use nor connection or adapter, then you need to override this method.
  589. /// </remarks>
  590. public virtual void FillTableSchema(DataTable table, string selectCommand,
  591. CommandParameterCollection parameters)
  592. {
  593. DbConnection conn = GetConnection();
  594. try
  595. {
  596. OpenConnection(conn);
  597. // prepare select command
  598. selectCommand = PrepareSelectCommand(selectCommand, table.TableName, conn);
  599. // read the table schema
  600. using (DbDataAdapter adapter = GetAdapter(selectCommand, conn, parameters))
  601. {
  602. adapter.SelectCommand.CommandTimeout = CommandTimeout;
  603. adapter.FillSchema(table, SchemaType.Source);
  604. }
  605. }
  606. finally
  607. {
  608. DisposeConnection(conn);
  609. }
  610. }
  611. /// <summary>
  612. /// Fills the table data.
  613. /// </summary>
  614. /// <param name="table">DataTable to fill.</param>
  615. /// <param name="selectCommand">The SQL select command.</param>
  616. /// <param name="parameters">SQL parameters.</param>
  617. /// <remarks>
  618. /// Usually you don't need to use this method. Internally it uses the <see cref="GetConnection"/> and
  619. /// <see cref="GetAdapter"/> methods to fill the table data. If you create own connection component
  620. /// that does not use nor connection or adapter, then you need to override this method.
  621. /// </remarks>
  622. public virtual void FillTableData(DataTable table, string selectCommand,
  623. CommandParameterCollection parameters)
  624. {
  625. DbConnection conn = GetConnection();
  626. try
  627. {
  628. OpenConnection(conn);
  629. // prepare select command
  630. selectCommand = PrepareSelectCommand(selectCommand, table.TableName, conn);
  631. // read the table
  632. using (DbDataAdapter adapter = GetAdapter(selectCommand, conn, parameters))
  633. {
  634. adapter.SelectCommand.CommandTimeout = CommandTimeout;
  635. table.Clear();
  636. adapter.Fill(table);
  637. }
  638. }
  639. finally
  640. {
  641. DisposeConnection(conn);
  642. }
  643. }
  644. /// <summary>
  645. /// Creates table.
  646. /// For internal use only.
  647. /// </summary>
  648. public virtual void CreateTable(TableDataSource source)
  649. {
  650. if (source.Table == null)
  651. {
  652. source.Table = new DataTable(source.TableName);
  653. DataSet.Tables.Add(source.Table);
  654. }
  655. }
  656. internal virtual void FillTable(TableDataSource source)
  657. {
  658. if (source.Table != null)
  659. {
  660. bool parametersChanged = false;
  661. foreach (CommandParameter par in source.Parameters)
  662. {
  663. object value = par.Value;
  664. if (!Object.Equals(value, par.LastValue))
  665. {
  666. par.LastValue = value;
  667. parametersChanged = true;
  668. }
  669. }
  670. if (source.ForceLoadData || source.Table.Rows.Count == 0 || parametersChanged)
  671. FillTableData(source.Table, source.SelectCommand, source.Parameters);
  672. }
  673. }
  674. /// <summary>
  675. /// Deletes table.
  676. /// For internal use only.
  677. /// </summary>
  678. public virtual void DeleteTable(TableDataSource source)
  679. {
  680. if (source.Table != null)
  681. {
  682. if (dataSet != null)
  683. dataSet.Tables.Remove(source.Table);
  684. source.Table.Dispose();
  685. source.Table = null;
  686. }
  687. }
  688. /// <summary>
  689. /// Clone table.
  690. /// For internal use only.
  691. /// </summary>
  692. public virtual void Clone()
  693. {
  694. XmlItem item = new XmlItem();
  695. using(FRWriter writer = new FRWriter(item))
  696. {
  697. writer.SerializeTo = SerializeTo.Clipboard;
  698. writer.BlobStore = new BlobStore(false);
  699. writer.Write(this);
  700. }
  701. using (FRReader reader = new FRReader(Report, item))
  702. {
  703. reader.DeserializeFrom = SerializeTo.Clipboard;
  704. reader.BlobStore = new BlobStore(false);
  705. var connection = Activator.CreateInstance(this.GetType()) as DataConnectionBase;
  706. connection.Parent = this.Parent;
  707. connection.SetReport(Report);
  708. reader.Read(connection);
  709. connection.CreateUniqueName();
  710. foreach (TableDataSource table in connection.Tables)
  711. table.CreateUniqueName();
  712. Report.Dictionary.AddChild(connection);
  713. }
  714. }
  715. protected void CreateUniqueNames(DataConnectionBase copyTo)
  716. {
  717. int i = 1;
  718. string s;
  719. do
  720. {
  721. s = this.Alias + i.ToString();
  722. i++;
  723. }
  724. while (Report.Dictionary.FindByAlias(s) != null);
  725. copyTo.Alias = s;
  726. copyTo.Name = s;
  727. }
  728. /// <inheritdoc/>
  729. public override void Serialize(FRWriter writer)
  730. {
  731. writer.ItemName = ClassName;
  732. if (Name != "")
  733. writer.WriteStr("Name", Name);
  734. if (Restrictions != Restrictions.None)
  735. writer.WriteValue("Restrictions", Restrictions);
  736. if (!String.IsNullOrEmpty(ConnectionString))
  737. writer.WriteStr("ConnectionString", Crypter.EncryptString(ConnectionString));
  738. if (!String.IsNullOrEmpty(ConnectionStringExpression))
  739. writer.WriteStr("ConnectionStringExpression", ConnectionStringExpression);
  740. if (LoginPrompt)
  741. writer.WriteBool("LoginPrompt", true);
  742. if (CommandTimeout != 30)
  743. writer.WriteInt("CommandTimeout", CommandTimeout);
  744. if (writer.SaveChildren)
  745. {
  746. foreach (TableDataSource c in Tables)
  747. {
  748. if (c.Enabled)
  749. writer.Write(c);
  750. }
  751. }
  752. }
  753. /// <inheritdoc/>
  754. public override string[] GetExpressions()
  755. {
  756. return new string[] { ConnectionStringExpression };
  757. }
  758. #endregion
  759. /// <summary>
  760. /// Initializes a new instance of the <see cref="DataConnectionBase"/> class with default settings.
  761. /// </summary>
  762. public DataConnectionBase()
  763. {
  764. tables = new TableCollection(this);
  765. connectionString = "";
  766. connectionStringExpression = "";
  767. IsSqlBased = true;
  768. commandTimeout = 30;
  769. SetFlags(Flags.CanEdit, true);
  770. }
  771. }
  772. }