#c# #oop #asynchronous #ado.net
#c# #ооп #асинхронный #ado.net
Вопрос:
Я уже создал группу классов, которые будут отвечать за получение данных и сохранение их в источнике. и я хочу добавить возможности асинхронности в эти классы, но я слаб в асинхронном программировании и не знаю, как лучше всего это реализовать. Я написал пример того, что я пытаюсь сделать
Как наилучшим образом реализовать асинхронные методы?
это основной класс:
public sealed class SourceManager : IDisposable
{
public SourceManager(string connectionString)
{
ConnectionString = connectionString;
MainDataSet = new DataSet();
Elements = new List<SourceElement>();
// this is for example
Elements.Add(new SourceElement(this, "Table1"));
Elements.Add(new SourceElement(this, "Table2"));
Elements.Add(new SourceElement(this, "Table3"));
Elements.Add(new SourceElement(this, "Table4"));
}
public void Dispose()
{
MainDataSet?.Dispose();
Elements?.ForEach(element => element.Dispose());
}
public DataSet MainDataSet { get; }
public string ConnectionString { get; }
public List<SourceElement> Elements { get; }
public void LoadElements()
{
Elements.ForEach(element => element.Load());
}
public Task LoadElementsAsync()
{
throw new NotImplementedException();
}
public void UpdateAll()
{
Elements.ForEach(element => element.Update());
}
public void UpdateAllAsync()
{
throw new NotImplementedException();
}
}
это класс element :
public sealed class SourceElement : IDisposable
{
private readonly SqlDataAdapter _adapter;
public SourceElement(SourceManager parentManager, string tableName)
{
ParentManager = parentManager;
TableName = tableName;
_adapter = new SqlDataAdapter($"SELECT * FROM [{TableName}];",
ParentManager.ConnectionString);
_adapter.FillSchema(ParentManager.MainDataSet, SchemaType.Mapped,
TableName);
}
public void Dispose()
{
_adapter?.Dispose();
}
public string TableName { get; }
private SourceManager ParentManager { get; }
public void Load()
{
_adapter.Fill(ParentManager.MainDataSet, TableName);
}
public Task LoadAsync()
{
throw new NotImplementedException();
}
public void Update()
{
_adapter.Update(ParentManager.MainDataSet.Tables[TableName]);
}
public Task UpdateAsync()
{
throw new NotImplementedException();
}
}
и вот как я это использую
public partial class Form1 : Form
{
private SourceManager sourceManager;
public Form1()
{
InitializeComponent();
// here we initialize the sourceManager cuz we need its elements
on draw the controls in the form
sourceManager = new
SourceManager("Server=myServerAddress;Database=myDataBase;User
Id=myUsername;Password=myPassword;");
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// here I want to fill the data tables without interrupting the interface
// I need to show a progress
sourceManager.LoadElementsAsync();
}
public void SaveAll()
{
// Here I I want to save the data without interrupting the interface thread
sourceManager.UpdateAllAsync();
}
public void SaveData(string tableName)
{
// Here I I want to save the data without interrupting the interface thread
sourceManager.Elements.Find(element => element.TableName.Equals(tableName))?.UpdateAsync();
}
}
Ответ №1:
SqlDataAdapter не имеет асинхронных методов. Вам придется реализовать это самостоятельно, чего я не рекомендую.
пример
await Task.Run(() =>_adapter.Fill(ParentManager.MainDataSet, TableName));
Но я бы рассмотрел альтернативное решение, используя другие ADO.NET библиотекам нравится использовать асинхронный SqlDataReader.
пример
public async Task SomeAsyncMethod()
{
using (var connection = new SqlConnection("YOUR CONNECTION STRING"))
{
await connection.OpenAsync();
using (var command = connection.CreateCommand())
{
command.CommandText = "YOUR QUERY";
var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
// read from reader
}
}
}
}
Посмотрите раздел Асинхронные функции программирования, добавленные в .NET Framework 4.5
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/asynchronous-programming
Но я бы, вероятно, даже не стал беспокоиться об этом и просто использовал Dapper, который поддерживает асинхронные методы, без необходимости писать весь шаблонный код.
Ответ №2:
Реализуйте асинхронные версии ваших методов следующим образом:
public async Task LoadElementsAsync()
{
await Task.Factory.StartNew(LoadElements);
}