using System;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
namespace Npgsql;
///
/// Represents the method that handles the events.
///
/// The source of the event.
/// An that contains the event data.
public delegate void NpgsqlRowUpdatedEventHandler(object sender, NpgsqlRowUpdatedEventArgs e);
///
/// Represents the method that handles the events.
///
/// The source of the event.
/// An that contains the event data.
public delegate void NpgsqlRowUpdatingEventHandler(object sender, NpgsqlRowUpdatingEventArgs e);
///
/// This class represents an adapter from many commands: select, update, insert and delete to fill a .
///
[System.ComponentModel.DesignerCategory("")]
public sealed class NpgsqlDataAdapter : DbDataAdapter
{
///
/// Row updated event.
///
public event NpgsqlRowUpdatedEventHandler? RowUpdated;
///
/// Row updating event.
///
public event NpgsqlRowUpdatingEventHandler? RowUpdating;
///
/// Default constructor.
///
public NpgsqlDataAdapter() {}
///
/// Constructor.
///
///
public NpgsqlDataAdapter(NpgsqlCommand selectCommand)
=> SelectCommand = selectCommand;
///
/// Constructor.
///
///
///
public NpgsqlDataAdapter(string selectCommandText, NpgsqlConnection selectConnection)
: this(new NpgsqlCommand(selectCommandText, selectConnection)) {}
///
/// Constructor.
///
///
///
public NpgsqlDataAdapter(string selectCommandText, string selectConnectionString)
: this(selectCommandText, new NpgsqlConnection(selectConnectionString)) {}
///
/// Create row updated event.
///
protected override RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand? command,
System.Data.StatementType statementType,
DataTableMapping tableMapping)
=> new NpgsqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
///
/// Create row updating event.
///
protected override RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand? command,
System.Data.StatementType statementType,
DataTableMapping tableMapping)
=> new NpgsqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
///
/// Raise the RowUpdated event.
///
///
protected override void OnRowUpdated(RowUpdatedEventArgs value)
{
//base.OnRowUpdated(value);
if (value is NpgsqlRowUpdatedEventArgs args)
RowUpdated?.Invoke(this, args);
//if (RowUpdated != null && value is NpgsqlRowUpdatedEventArgs args)
// RowUpdated(this, args);
}
///
/// Raise the RowUpdating event.
///
///
protected override void OnRowUpdating(RowUpdatingEventArgs value)
{
if (value is NpgsqlRowUpdatingEventArgs args)
RowUpdating?.Invoke(this, args);
}
///
/// Delete command.
///
public new NpgsqlCommand? DeleteCommand
{
get => (NpgsqlCommand?)base.DeleteCommand;
set => base.DeleteCommand = value;
}
///
/// Select command.
///
public new NpgsqlCommand? SelectCommand
{
get => (NpgsqlCommand?)base.SelectCommand;
set => base.SelectCommand = value;
}
///
/// Update command.
///
public new NpgsqlCommand? UpdateCommand
{
get => (NpgsqlCommand?)base.UpdateCommand;
set => base.UpdateCommand = value;
}
///
/// Insert command.
///
public new NpgsqlCommand? InsertCommand
{
get => (NpgsqlCommand?)base.InsertCommand;
set => base.InsertCommand = value;
}
// Temporary implementation, waiting for official support in System.Data via https://github.com/dotnet/runtime/issues/22109
internal async Task Fill(DataTable dataTable, bool async, CancellationToken cancellationToken = default)
{
var command = SelectCommand;
var activeConnection = command?.Connection ?? throw new InvalidOperationException("Connection required");
var originalState = ConnectionState.Closed;
try
{
originalState = activeConnection.State;
if (ConnectionState.Closed == originalState)
await activeConnection.Open(async, cancellationToken);
var dataReader = await command.ExecuteReader(CommandBehavior.Default, async, cancellationToken);
try
{
return await Fill(dataTable, dataReader, async, cancellationToken);
}
finally
{
if (async)
await dataReader.DisposeAsync();
else
dataReader.Dispose();
}
}
finally
{
if (ConnectionState.Closed == originalState)
activeConnection.Close();
}
}
async Task Fill(DataTable dataTable, NpgsqlDataReader dataReader, bool async, CancellationToken cancellationToken = default)
{
dataTable.BeginLoadData();
try
{
var rowsAdded = 0;
var count = dataReader.FieldCount;
var columnCollection = dataTable.Columns;
for (var i = 0; i < count; ++i)
{
var fieldName = dataReader.GetName(i);
if (!columnCollection.Contains(fieldName))
{
var fieldType = dataReader.GetFieldType(i);
var dataColumn = new DataColumn(fieldName, fieldType);
columnCollection.Add(dataColumn);
}
}
var values = new object[count];
while (async ? await dataReader.ReadAsync(cancellationToken) : dataReader.Read())
{
dataReader.GetValues(values);
dataTable.LoadDataRow(values, true);
rowsAdded++;
}
return rowsAdded;
}
finally
{
dataTable.EndLoadData();
}
}
}
#pragma warning disable 1591
public class NpgsqlRowUpdatingEventArgs : RowUpdatingEventArgs
{
public NpgsqlRowUpdatingEventArgs(DataRow dataRow, IDbCommand? command, System.Data.StatementType statementType,
DataTableMapping tableMapping)
: base(dataRow, command, statementType, tableMapping) {}
}
public class NpgsqlRowUpdatedEventArgs : RowUpdatedEventArgs
{
public NpgsqlRowUpdatedEventArgs(DataRow dataRow, IDbCommand? command, System.Data.StatementType statementType,
DataTableMapping tableMapping)
: base(dataRow, command, statementType, tableMapping) {}
}
#pragma warning restore 1591