Skip to content

Commit 7be5323

Browse files
committed
Implement MySqlDataAdapter. Fixes #183
1 parent 58d33b8 commit 7be5323

File tree

3 files changed

+285
-5
lines changed

3 files changed

+285
-5
lines changed

src/MySqlConnector/MySql.Data.MySqlClient/MySqlCommand.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,7 @@ public override CommandType CommandType
138138

139139
public override bool DesignTimeVisible { get; set; }
140140

141-
public override UpdateRowSource UpdatedRowSource
142-
{
143-
get { throw new NotSupportedException(); }
144-
set { throw new NotSupportedException(); }
145-
}
141+
public override UpdateRowSource UpdatedRowSource { get; set; }
146142

147143
public long LastInsertedId { get; internal set; }
148144

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#if !NETSTANDARD1_3
2+
using System.Data;
3+
using System.Data.Common;
4+
5+
namespace MySql.Data.MySqlClient
6+
{
7+
public sealed class MySqlDataAdapter : DbDataAdapter
8+
{
9+
public MySqlDataAdapter()
10+
{
11+
}
12+
13+
public MySqlDataAdapter(MySqlCommand selectCommand) => SelectCommand = selectCommand;
14+
15+
public MySqlDataAdapter(string selectCommandText, MySqlConnection connection)
16+
: this(new MySqlCommand(selectCommandText, connection))
17+
{
18+
}
19+
20+
public MySqlDataAdapter(string selectCommandText, string connectionString)
21+
: this(new MySqlCommand(selectCommandText, new MySqlConnection(connectionString)))
22+
{
23+
}
24+
25+
public event MySqlRowUpdatingEventHandler RowUpdating;
26+
27+
public event MySqlRowUpdatedEventHandler RowUpdated;
28+
29+
public new MySqlCommand DeleteCommand
30+
{
31+
get => (MySqlCommand) base.DeleteCommand;
32+
set => base.DeleteCommand = value;
33+
}
34+
35+
public new MySqlCommand InsertCommand
36+
{
37+
get => (MySqlCommand) base.InsertCommand;
38+
set => base.InsertCommand = value;
39+
}
40+
41+
public new MySqlCommand SelectCommand
42+
{
43+
get => (MySqlCommand) base.SelectCommand;
44+
set => base.SelectCommand = value;
45+
}
46+
47+
public new MySqlCommand UpdateCommand
48+
{
49+
get => (MySqlCommand) base.UpdateCommand;
50+
set => base.UpdateCommand = value;
51+
}
52+
53+
protected override void OnRowUpdating(RowUpdatingEventArgs value) => RowUpdating?.Invoke(this, (MySqlRowUpdatingEventArgs) value);
54+
55+
protected override void OnRowUpdated(RowUpdatedEventArgs value) => RowUpdated?.Invoke(this, (MySqlRowUpdatedEventArgs) value);
56+
57+
protected override RowUpdatingEventArgs CreateRowUpdatingEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) => new MySqlRowUpdatingEventArgs(dataRow, command, statementType, tableMapping);
58+
59+
protected override RowUpdatedEventArgs CreateRowUpdatedEvent(DataRow dataRow, IDbCommand command, StatementType statementType, DataTableMapping tableMapping) => new MySqlRowUpdatedEventArgs(dataRow, command, statementType, tableMapping);
60+
}
61+
62+
public delegate void MySqlRowUpdatingEventHandler(object sender, MySqlRowUpdatingEventArgs e);
63+
64+
public delegate void MySqlRowUpdatedEventHandler(object sender, MySqlRowUpdatedEventArgs e);
65+
66+
public sealed class MySqlRowUpdatingEventArgs : RowUpdatingEventArgs
67+
{
68+
public MySqlRowUpdatingEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
69+
: base(row, command, statementType, tableMapping)
70+
{
71+
}
72+
73+
public new MySqlCommand Command => (MySqlCommand) base.Command;
74+
}
75+
76+
public sealed class MySqlRowUpdatedEventArgs : RowUpdatedEventArgs
77+
{
78+
public MySqlRowUpdatedEventArgs(DataRow row, IDbCommand command, StatementType statementType, DataTableMapping tableMapping)
79+
: base(row, command, statementType, tableMapping)
80+
{
81+
}
82+
83+
public new MySqlCommand Command => (MySqlCommand) base.Command;
84+
}
85+
}
86+
#endif

tests/SideBySide/DataAdapterTests.cs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#if !NETCOREAPP1_1_2
2+
using System;
3+
using System.Data;
4+
using Dapper;
5+
using MySql.Data.MySqlClient;
6+
using Xunit;
7+
8+
namespace SideBySide
9+
{
10+
public class DataAdapterTests : IClassFixture<DatabaseFixture>, IDisposable
11+
{
12+
public DataAdapterTests(DatabaseFixture database)
13+
{
14+
m_connection = database.Connection;
15+
m_connection.Open();
16+
17+
#if BASELINE
18+
// not sure why this is necessary
19+
m_connection.Execute("drop table if exists data_adapter;");
20+
#endif
21+
22+
m_connection.Execute(@"
23+
create temporary table data_adapter(
24+
id bigint not null primary key auto_increment,
25+
int_value int null,
26+
text_value text null
27+
);
28+
insert into data_adapter(int_value, text_value) values
29+
(null, null),
30+
(0, ''),
31+
(1, 'one');
32+
");
33+
}
34+
35+
public void Dispose()
36+
{
37+
m_connection.Close();
38+
}
39+
40+
[Fact]
41+
public void UseDataAdapter()
42+
{
43+
using (var command = new MySqlCommand("SELECT 1", m_connection))
44+
using (var da = new MySqlDataAdapter())
45+
using (var ds = new DataSet())
46+
{
47+
da.SelectCommand = command;
48+
da.Fill(ds);
49+
Assert.Single(ds.Tables);
50+
Assert.Single(ds.Tables[0].Rows);
51+
Assert.Single(ds.Tables[0].Rows[0].ItemArray);
52+
Assert.Equal(1L, ds.Tables[0].Rows[0][0]);
53+
}
54+
}
55+
56+
[Fact]
57+
public void UseDataAdapterMySqlConnectionConstructor()
58+
{
59+
using (var command = new MySqlCommand("SELECT 1", m_connection))
60+
using (var da = new MySqlDataAdapter(command))
61+
using (var ds = new DataSet())
62+
{
63+
da.Fill(ds);
64+
Assert.Equal(1L, ds.Tables[0].Rows[0][0]);
65+
}
66+
}
67+
68+
[Fact]
69+
public void UseDataAdapterStringMySqlConnectionConstructor()
70+
{
71+
using (var da = new MySqlDataAdapter("SELECT 1", m_connection))
72+
using (var ds = new DataSet())
73+
{
74+
da.Fill(ds);
75+
Assert.Equal(1L, ds.Tables[0].Rows[0][0]);
76+
Assert.Equal(1L, ds.Tables[0].Rows[0][0]);
77+
}
78+
}
79+
80+
[Fact]
81+
public void UseDataAdapterStringStringConstructor()
82+
{
83+
using (var da = new MySqlDataAdapter("SELECT 1", AppConfig.ConnectionString))
84+
using (var ds = new DataSet())
85+
{
86+
da.Fill(ds);
87+
Assert.Equal(1L, ds.Tables[0].Rows[0][0]);
88+
}
89+
}
90+
91+
[Fact]
92+
public void Fill()
93+
{
94+
using (var da = new MySqlDataAdapter("select * from data_adapter", m_connection))
95+
using (var ds = new DataSet())
96+
{
97+
da.Fill(ds, "data_adapter");
98+
99+
Assert.Single(ds.Tables);
100+
Assert.Equal(3, ds.Tables[0].Rows.Count);
101+
102+
Assert.Equal(1L, ds.Tables[0].Rows[0]["id"]);
103+
Assert.Equal(2L, ds.Tables[0].Rows[1]["id"]);
104+
Assert.Equal(3L, ds.Tables[0].Rows[2]["id"]);
105+
106+
Assert.Equal(DBNull.Value, ds.Tables[0].Rows[0]["int_value"]);
107+
Assert.Equal(0, ds.Tables[0].Rows[1]["int_value"]);
108+
Assert.Equal(1, ds.Tables[0].Rows[2]["int_value"]);
109+
110+
Assert.Equal(DBNull.Value, ds.Tables[0].Rows[0]["text_value"]);
111+
Assert.Equal("", ds.Tables[0].Rows[1]["text_value"]);
112+
Assert.Equal("one", ds.Tables[0].Rows[2]["text_value"]);
113+
}
114+
}
115+
116+
[Fact]
117+
public void LoadDataTable()
118+
{
119+
using (var command = new MySqlCommand("SELECT * FROM data_adapter", m_connection))
120+
using (var dr = command.ExecuteReader())
121+
{
122+
var dt = new DataTable();
123+
dt.Load(dr);
124+
dr.Close();
125+
126+
Assert.Equal(3, dt.Rows.Count);
127+
128+
Assert.Equal(1L, dt.Rows[0]["id"]);
129+
Assert.Equal(2L, dt.Rows[1]["id"]);
130+
Assert.Equal(3L, dt.Rows[2]["id"]);
131+
132+
Assert.Equal(DBNull.Value, dt.Rows[0]["int_value"]);
133+
Assert.Equal(0, dt.Rows[1]["int_value"]);
134+
Assert.Equal(1, dt.Rows[2]["int_value"]);
135+
136+
Assert.Equal(DBNull.Value, dt.Rows[0]["text_value"]);
137+
Assert.Equal("", dt.Rows[1]["text_value"]);
138+
Assert.Equal("one", dt.Rows[2]["text_value"]);
139+
}
140+
}
141+
142+
[SkippableFact(Baseline = "Throws FormatException: Input string was not in a correct format")]
143+
public void InsertWithDataSet()
144+
{
145+
using (var ds = new DataSet())
146+
using (var da = new MySqlDataAdapter("SELECT * FROM data_adapter", m_connection))
147+
{
148+
da.Fill(ds);
149+
150+
da.InsertCommand = new MySqlCommand("INSERT INTO data_adapter (int_value, text_value) VALUES (@int, @text)", m_connection);
151+
152+
da.InsertCommand.Parameters.Add(new MySqlParameter("@int", DbType.Int32));
153+
da.InsertCommand.Parameters.Add(new MySqlParameter("@text", DbType.String));
154+
155+
da.InsertCommand.Parameters[0].Direction = ParameterDirection.Input;
156+
da.InsertCommand.Parameters[1].Direction = ParameterDirection.Input;
157+
158+
da.InsertCommand.Parameters[0].SourceColumn = "int_value";
159+
da.InsertCommand.Parameters[1].SourceColumn = "text_value";
160+
161+
var dt = ds.Tables[0];
162+
var dr = dt.NewRow();
163+
dr["int_value"] = 4;
164+
dr["text_value"] = "four";
165+
dt.Rows.Add(dr);
166+
167+
using (var ds2 = ds.GetChanges())
168+
{
169+
da.Update(ds2);
170+
171+
ds.Merge(ds2);
172+
ds.AcceptChanges();
173+
}
174+
}
175+
176+
using (var cmd2 = new MySqlCommand("SELECT id, int_value, text_value FROM data_adapter", m_connection))
177+
using (var dr2 = cmd2.ExecuteReader())
178+
{
179+
Assert.True(dr2.Read());
180+
Assert.Equal(1L, dr2[0]);
181+
182+
Assert.True(dr2.Read());
183+
Assert.Equal(2L, dr2[0]);
184+
185+
Assert.True(dr2.Read());
186+
Assert.Equal(3L, dr2[0]);
187+
188+
Assert.True(dr2.Read());
189+
Assert.Equal(4L, dr2[0]);
190+
Assert.Equal(4, dr2[1]);
191+
Assert.Equal("four", dr2[2]);
192+
}
193+
}
194+
195+
readonly MySqlConnection m_connection;
196+
}
197+
}
198+
#endif

0 commit comments

Comments
 (0)