Heim  >  Artikel  >  Backend-Entwicklung  >  Implementierungsmethode zum direkten Ausführen von SQL-Anweisungen und zum Generieren von DataTable unter .Net Core

Implementierungsmethode zum direkten Ausführen von SQL-Anweisungen und zum Generieren von DataTable unter .Net Core

高洛峰
高洛峰Original
2016-12-20 14:24:062353Durchsuche

.net Core kann SQL-Anweisungen ausführen, aber nur stark typisierte Rückgabeergebnisse generieren. Zum Beispiel var blogs = context.Blogs.FromSql("SELECT * FROM dbo.Blogs").ToList(). Es ist nicht erlaubt, schwache Typen wie DataSet und DataTable zurückzugeben. Aus diesem Grund ist DataTable möglicherweise nicht im .net-Kern implementiert, DataTable kann jedoch weiterhin verwendet werden. Wir haben hier eine Data-Warehouse-Anforderung, die es Benutzern ermöglicht, selbst SQL-ähnliche Anweisungen zu schreiben, sie dann auszuführen und in Tabellen anzuzeigen. Da sich die Anweisungen ständig ändern, weiß ich nicht, was die Anweisung des Benutzers ausgibt, und ich kann sie nicht nach Typ definieren, sodass ich nur die DataTable-Methode verwenden kann.

Zuvor konnte die Datentabelle unter dem .net-Framework einfach über dataadpater ausgefüllt werden, und dann konnten die Daten in der Datentabelle zur Anzeige an den Client übertragen werden. Unter .net Core gibt es jedoch keine DataTable und DataSet, und wir können MicroDataTable nur selbst implementieren.

Hier folgen wir auch der DataTable-Methode. Die Spalten von MicroDataTable sind als MicroDataColumn und die Zeilen als MicroDataRow definiert. Der Code lautet wie folgt:

public class MicroDataTable
{ /// <summary>
/// 整个查询语句结果的总条数,而非本DataTable的条数
/// </summary>
public int TotalCount { get; set; }
public List<MicroDataColumn> Columns { get; set; } = new List<MicroDataColumn>();
public List<MicroDataRow> Rows { get; set; } = new List<MicroDataRow>();
public MicroDataColumn[] PrimaryKey { get; set; }
public MicroDataRow NewRow()
{
return new MicroDataRow(this.Columns, new object[Columns.Count]);
}
}
public class MicroDataColumn
{
public string ColumnName { get; set; }
public Type ColumnType { get; set; }
}
public class MicroDataRow
{
private object[] _ItemArray;
public List<MicroDataColumn> Columns { get; private set; }
public MicroDataRow(List<MicroDataColumn> columns, object[] itemArray)
{
this.Columns = columns;
this._ItemArray = itemArray;
}
public object this[int index]
{
get { return _ItemArray[index]; }
set { _ItemArray[index] = value; }
}
public object this[string columnName]
{
get
{
int i = 0;
foreach (MicroDataColumn column in Columns)
{
if (column.ColumnName == columnName)
break;
i++;
}
return _ItemArray[i];
}
set
{
int i = 0;
foreach (MicroDataColumn column in Columns)
{
if (column.ColumnName == columnName)
break;
i++;
}
_ItemArray[i] = value;
}
}
}

Es ist zu beachten, dass sich das TotalCount-Attribut im Fall von Paging auf die Anzahl aller Datensätze bezieht, die von der Abfrageanweisung in der Datenbank abgefragt werden, während die Daten von MicroDataTable ist der Datensatz der aktuellen Seite.

Um die DataTable aus der Datenbank abzurufen, verwenden Sie eine SqlHelper-ähnliche Methode, um die ExecuteDataTable-Erweiterungsmethode von DbContext zu schreiben, übergeben Sie die SQL-Anweisung und die Parameter der SQL-Anweisung und generieren Sie die MicroDataTable:

public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, params object[] parameters)
{
var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
}
}
public static MicroDataTable ExecuteDataTable(this DbContext context, string sql, int pageIndex, int pageSize, params object[] parameters)
{
var concurrencyDetector = context.Database.GetService<IConcurrencyDetector>();
using (concurrencyDetector.EnterCriticalSection())
{
var rawSqlCommand = context.Database.GetService<IRawSqlCommandBuilder>().Build(sql, parameters);
RelationalDataReader query = rawSqlCommand.RelationalCommand.ExecuteReader(context.Database.GetService<IRelationalConnection>(), parameterValues: rawSqlCommand.ParameterValues);
return MicroDataTableHelper.FillDataTable(query.DbDataReader, 0, int.MaxValue);
}
}

Diese Methode erfordert noch einige Kernkenntnisse des .net-Frameworks. Der Prozess besteht darin, einen nativen SQLCommand basierend auf SQL und Parametern zu erstellen, die ExecuteReader-Methode auszuführen, um den DataReader zurückzugeben, und dann den DataReader in die MicroDataTable zu füllen. Beachten Sie, dass die Beschreibung von IConcurrencyDetector in .net Core wie folgt lautet: Diese API unterstützt die Entity Framework Core-Infrastruktur und ist nicht für die direkte Verwendung in Ihrem Code vorgesehen. Diese API kann sich in zukünftigen Versionen ändern oder entfernt werden. Wir können es zunächst nur auf diese Weise implementieren und prüfen, ob ef.core geändert werden kann oder später eine bessere Möglichkeit gegeben werden kann.

Im obigen Programm steht am Ende ein Satz MicroDataTableHelper.FillDataTable. Die Hauptfunktion dieser Methode besteht darin, die MicroDataTable aus dem DataReader auszufüllen.

public static MicroDataTable FillDataTable(DbDataReader reader, int pageIndex, int pageSize)
{
bool defined = false;
MicroDataTable table = new MicroDataTable();
int index = 0;
int beginIndex = pageSize * pageIndex;
int endIndex = pageSize * (pageIndex + 1) - 1;
while (reader.Read())
{
object[] values = new object[reader.FieldCount];
if (!defined)
{
for (int i = 0; i < reader.FieldCount; i++)
{
MicroDataColumn column = new MicroDataColumn()
{
ColumnName = reader.GetName(i),
ColumnType = reader.GetFieldType(i)
};
table.Columns.Add(column);
}
defined = true;
}
if (index >= beginIndex && index <= endIndex)
{
reader.GetValues(values);
table.Rows.Add(new MicroDataRow(table.Columns, values));
}
index++;
}
table.TotalCount = index;
return table;
}

Das obige Programm ist Schritt für Schritt geschrieben und sollte nicht sehr effizient sein. Ich hatte in letzter Zeit wenig Zeit und habe die ursprüngliche Datatable-Lademethode nicht analysiert. Ich werde in Zukunft Zeit haben, sie zu optimieren.

Das Folgende ist ein Programm, das das .net-Framework verwendet, um Paging-Daten vom Datenleser zur Datentabelle zu erhalten, nur als Referenz. Zu diesem Zeitpunkt verwendete dieses Programm die Methode table.beginloaddata/endloaddata und die Effizienz wurde erheblich verbessert.

using (IDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
int fieldCount = reader.FieldCount;
for (int i = 0; i < fieldCount; i++)
{
table.Columns.Add(reader.GetName(i), reader.GetFieldType(i));
}
object[] values = new object[fieldCount];
int currentIndex = 0;
int startIndex = pageSize * pageIndex;
try
{
table.BeginLoadData();
while (reader.Read())
{
if (startIndex > currentIndex++)
continue;
if (pageSize > 0 && (currentIndex - startIndex) > pageSize)
break;
reader.GetValues(values);
table.LoadDataRow(values, true);
}
}
finally
{
table.EndLoadData();
try //lgy:由于连接阿里云ADS数据库cmd.Cancel()会报错,所以把错误忽略了。
{
cmd.Cancel();
}
catch
{ 
}
reader.Close();
}
}

Das Obige hat Ihnen der Editor vorgestellt, um SQL-Anweisungen direkt auszuführen und DataTable unter .Net Core zu generieren. Ich hoffe, es wird für alle hilfreich sein. Ich möchte mich auch bei Ihnen allen für Ihre Unterstützung der chinesischen PHP-Website bedanken!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn