web-dev-qa-db-ja.com

エンティティフレームワークでカスタムSQLを実行しますか?

データベースのどこかに保存されるカスタムクエリを実行する必要があり、データテーブルまたはデータセットに返して、列をtrueに自動生成するグリッドビューにバインドする必要があります。

私のすべてのデータアクセス層はエンティティフレームワークで完全に機能しますが、特定のシナリオではこれを行う必要があり、ado.netをエンティティフレームワークと組み合わせる必要があるのか​​、それともEFが何らかの方法でそれを行うことができるのか疑問に思います

8
Luis Valencia

目標がADO.NET構造(DataTableまたはDataSet)を返すことである場合は、従来のADO.NETを使用してください。データをエンティティセットにバインドしてから、DataTableまたはDataSetに自分でデータを入力するよりも簡単です。

ただし、EntityFrameworkを介してカスタムクエリを実行することに本当に興味がある場合は、 ExecuteQuery を参照してください。これにより、SQLクエリを実行し、結果をモデル内のエンティティにマップして戻すことができます。次に、IEnumerableの結果を取得し、それをDataTableまたはDataSetにマップするのはあなたの側の演習になります。したがって、「古き良きADO.NETメソッドを使用して実行する」という私の最初の答えです。

8
villecoder

Entity Framework 5の場合

context.Database.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();


}
18

別の側面とより簡単なアプローチがあります。 EntityFrameworkコンテキストを使用して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接続を使用してクエリを実行できます。

これは、動的に何かを行う場合や、エンティティにマップできない場合に非常に役立ちます。たとえば、DataTableで物事を取得できます。

上記の構文はEF 5.用です。

12
Peru

私はEF6を使用しており、ある日、動的SQL文字列を実行してDataTableを取得する方法が必要でした。まず、DbContext.Database.ConnectionSqlConnectionにキャストするだけで、すべての作業を行いました。テストでは機能しましたが、使用しているGlimpseがタイプGlimpse.Ado.AlternateType.GlimpseDbConnectionDbConnectionの自己実装を挿入したため、アプリケーションが壊れていました。 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.ConnectionSqlConnectionであるテスト、およびGlimpse.Ado.AlternateType.GlimpseDbConnectionの場合

3
Alezis