我需要执行一个自定义查询,该查询将保存在数据库中的某个位置,并且我需要它在 DataTable 或 DataSet 中返回并将其绑定到 GridView,该 GridView 将自动生成列设置为
true
。
我的所有数据访问层都可以与实体框架完美配合,但对于某些特定场景,我需要这样做,我想知道是否应该将 ADO.NET 与实体框架结合起来,或者 EF 是否可以以某种方式做到这一点。
对于 Entity Framework 5 使用
上下文.数据库.SqlQuery
对于 Entity Framework 4 使用以下代码
context.ExecuteStoreQuery
public string BuyerSequenceNumberMax(int buyerId)
{
string sequenceMaxQuery = "SELECT TOP(1) btitosal.BuyerSequenceNumber FROM BuyerTakenItemToSale btitosal " +
"WHERE btitosal.BuyerID = " + buyerId +
"ORDER BY CONVERT(INT,SUBSTRING(btitosal.BuyerSequenceNumber,7, LEN(btitosal.BuyerSequenceNumber))) DESC";
var sequenceQueryResult = context.Database.SqlQuery<string>(sequenceMaxQuery).FirstOrDefault();
string buyerSequenceNumber = string.Empty;
if (sequenceQueryResult != null)
{
buyerSequenceNumber = sequenceQueryResult.ToString();
}
return buyerSequenceNumber;
}
要返回列表,请使用以下代码
public List<PanelSerialList> PanelSerialByLocationAndStock(string locationCode, byte storeLocation, string itemCategory, string itemCapacity, byte agreementType, string packageCode)
{
string panelSerialByLocationAndStockQuery = "SELECT isws.ItemSerialNo, im.ItemModel " +
"FROM Inv_ItemMaster im " +
"INNER JOIN " +
"Inv_ItemStockWithSerialNoByLocation isws " +
" ON im.ItemCode = isws.ItemCode " +
" WHERE isws.LocationCode = '" + locationCode + "' AND " +
" isws.StoreLocation = " + storeLocation + " AND " +
" isws.IsAvailableInStore = 1 AND " +
" im.ItemCapacity = '" + itemCapacity + "' AND " +
" isws.ItemSerialNo NOT IN ( " +
" Select sp.PanelSerialNo From Special_SpecialPackagePriceForResale sp " +
" Where sp.PackageCode = '" + packageCode + "' )";
context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList();
}
这是另一个维度和更简单的方法。使用实体框架上下文获取 SQL 连接:
var connection = (System.Data.SqlClient.SqlConnection) _db.Database.Connection;
if (connection != null && connection.State == ConnectionState.Closed)
{
connection.Open();
}
var dt = new DataTable();
using (var com = new System.Data.SqlClient.SqlDataAdapter("Select * from Table", connection))
{
com.Fill(dt);
}
我们可以使用
DataAdapter
或任何其他经典方法来使用 EF 连接执行查询。
当我们动态执行某些操作并且无法映射到实体时,这将非常有用。例如,我们可以在数据表中获取内容。
以上语法适用于 EF 5.0。
如果您的目标是返回 ADO.NET 结构(DataTable 或 DataSet),那么只需使用经典的 ADO.NET。您会发现这比尝试将数据绑定到实体集然后自己填充数据表或数据集更容易。
但是,如果您确实有兴趣通过 EntityFramework 运行自定义查询,请查看 ExecuteQuery。它允许您执行 SQL 查询并将结果映射回模型中的实体。然后,您将需要练习获取 IEnumerable 结果并将其映射到 DataTable 或 DataSet。因此,我最初的回答是“只需使用优秀的老式 ADO.NET 方法即可。”
我使用 EF6,有一天我需要一种方法来执行动态 SQL 字符串并获取 DataTable。首先,我只是将
DbContext.Database.Connection
投射到 SqlConnection
并完成了整个工作。它适用于测试,但应用程序被破坏了,因为我们使用的 Glimpse 注入了类型为 DbConnection
的 Glimpse.Ado.AlternateType.GlimpseDbConnection
的自我实现。我需要独立于 DbConnection 工作的方法。最后我得到以下代码:
public class SqlDataProvider : ISqlDataProvider
{
private readonly DbContext _context;
public SqlDataProvider(DbContext context)
{
_context = context;
}
public DataTable GetDataTable(string sqlQuery)
{
try
{
DbProviderFactory factory = DbProviderFactories.GetFactory(_context.Database.Connection);
using (var cmd = factory.CreateCommand())
{
cmd.CommandText = sqlQuery;
cmd.CommandType = CommandType.Text;
cmd.Connection = _context.Database.Connection;
using (var adapter = factory.CreateDataAdapter())
{
adapter.SelectCommand = cmd;
var tb = new DataTable();
adapter.Fill(tb);
return tb;
}
}
}
catch (Exception ex)
{
throw new SqlExecutionException(string.Format("Error occurred during SQL query execution {0}", sqlQuery), ex);
}
}
这适用于任何情况:对于
DbContext.Database.Connection
为 SqlConnection
的测试以及 Glimpse.Ado.AlternateType.GlimpseDbConnection
EF Core 8 更新(感谢 Peru 的最初想法)。
Microsoft.Data.SqlClient
是取代 System.Data.SqlClient
的新库。大多数数据可以通过 EF Core 获取,所以我无法想象需要其他工具来实现这一点,但我发现如果我想获取其他表(例如 SQL 系统表),这种方法很有用。
using (SqlConnection srcConn = new SqlConnection(_ctx.Database.GetConnectionString()))
using (SqlCommand srcCmd = new SqlCommand("select stopword from sys.fulltext_system_stopwords", srcConn))
{
srcConn.Open();
using (DbDataReader reader = srcCmd.ExecuteReader())
{
while (reader.Read())
{
_stopWords.Add(reader.GetFieldValue<string>(0));
}
}
}