【问题标题】:Is it possible to run native sql with entity framework?是否可以使用实体框架运行本机 sql?
【发布时间】:2009-05-27 12:04:26
【问题描述】:

我正在尝试在表中搜索 XML 字段,EF 不支持。

不使用纯 Ado.net 是否可以通过 EF 获得本机 SQL 支持?

【问题讨论】:

  • 请澄清您的问题。当您询问“本机 sql 支持”时,您的意思是否不仅仅是“支持 XML 列”?你还指什么?另外,您对 XML 列有什么问题?它只是没有进入实体,还是在您尝试使用它时出现问题?另外,请说您使用的是什么版本? 2008、2008 SP1、2010 CTP 还是 Beta 1?

标签: sql entity-framework ado.net


【解决方案1】:

对于 .NET Framework 版本 4 及更高版本:如果您的查询没有返回结果,请使用 ObjectContext.ExecuteStoreCommand(),如果您的查询返回结果,请使用 ObjectContext.ExecuteStoreQuery

对于以前的 .NET Framework 版本,这里有一个示例说明如何操作。如果您的查询返回结果,请根据需要替换 ExecuteNonQuery()。

static void ExecuteSql(ObjectContext c, string sql)
{
    var entityConnection = (System.Data.EntityClient.EntityConnection)c.Connection;
    DbConnection conn = entityConnection.StoreConnection;
    ConnectionState initialState = conn.State;
    try
    {
        if (initialState != ConnectionState.Open)
            conn.Open();  // open connection if not already open
        using (DbCommand cmd = conn.CreateCommand())
        {
            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
    }
    finally
    {
        if (initialState != ConnectionState.Open)
            conn.Close(); // only close connection if not initially open
    }
}

【讨论】:

  • 这个答案已经过时了。请参阅此帖子geekswithblogs.net/rgupta/archive/2010/06/23/…。您可以直接从实体框架执行 Sql,无需使用 Entity 实例的 ExecuteStoreCommandExecuteStoreQuery 包装器。
  • 请记住,DbContext 不支持这些方法,但是有 Database.ExecuteSqlCommand() 或 Database.SqlQuery
【解决方案2】:

使用Entity Framework 5.0可以使用ExecuteSqlCommand执行多行/多命令纯SQL语句。这样您就不需要提供任何支持对象来存储返回的值,因为该方法返回一个 int(执行命令后由数据库返回的结果)。

示例:

context.Database.ExecuteSqlCommand(@
"-- Script Date: 10/1/2012 3:34 PM  - Generated by ExportSqlCe version 3.5.2.18
SET IDENTITY_INSERT [Students] ON;

INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (12,N'First Name',N'SecondName',{ts '1988-03-02 00:00:00.000'},N'RUA 19 A, 60',N'MORADA DO VALE',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3346-7125',NULL,NULL,{ts '2011-06-04 21:25:26.000'},2,1);

INSERT INTO [Students] ([StudentId],[FirstName],[LastName],[BirthDate],[Address],[Neighborhood],[City],[State],[Phone],[MobilePhone],[Email],[Enrollment],[Gender],[Status]) VALUES (13,N'FirstName',N'LastName',{ts '1976-04-12 00:00:00.000'},N'RUA 201, 2231',N'RECANTO FELIZ',N'BARRA DO PIRAÍ',N'Rio de Janeiro',N'3341-6892',NULL,NULL,{ts '2011-06-04 21:38:38.000'},2,1);
");

有关更多信息,请查看此处:Entity Framework Code First: Executing SQL files on database creation

【讨论】:

    【解决方案3】:

    对于 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 + "' )";
    
    
        return context.Database.SqlQuery<PanelSerialList>(panelSerialByLocationAndStockQuery).ToList();
    
    
    }
    

    【讨论】:

      【解决方案4】:

      从 .NET 4 开始,您可以使用ExecuteStoreQuery 方法:

      var list = myDBEntities.ExecuteStoreQuery<MyClass>(MyClass.sql);
      

      myDBEntities 继承自 ObjectContext。

      class MyClass
      {
          /* You can change query to more complicated, e.g. with joins */
          public const string sql = @"select [MyTable].[MyField] from [MyTable]";
          public string MyField { get; set; }
      }
      

      注意 MyTable 是真实的表名,而不是 EF 类。

      【讨论】:

        【解决方案5】:

        保持简单

        using (var context = new MyDBEntities())
        {
            var m = context.ExecuteStoreQuery<MyDataObject>("Select * from Person", string.Empty);
            //Do anything you wonna do with 
            MessageBox.Show(m.Count().ToString());
        }
        

        【讨论】:

          【解决方案6】:
          public class RaptorRepository<T>
              where T : class
          {
              public RaptorRepository()
                  : this(new RaptorCoreEntities())
              {
              }
          
              public RaptorRepository(ObjectContext repositoryContext)
              {
                  _repositoryContext = repositoryContext ?? new RaptorCoreEntities();
                  _objectSet = repositoryContext.CreateObjectSet<T>();
              }
          
              private ObjectContext _repositoryContext;
              private ObjectSet<T> _objectSet;
              public ObjectSet<T> ObjectSet
              {
                  get
                  {
                      return _objectSet;
                  }
              }
          
          
              public void DeleteAll()
              {
                  _repositoryContext
                      .ExecuteStoreCommand("DELETE " + _objectSet.EntitySet.ElementType.Name);
              }
          }
          

          【讨论】:

            【解决方案7】:

            那么我们对 2017 年的这一切有什么看法? 80k 咨询表明在 EF 中运行 SQL 请求是很多人想做的事情。但为什么?有什么好处?

            贾斯汀,一位享有我 20 倍声誉的大师,在接受的答案中为我们提供了一种静态方法,该方法逐行查找,就像等效的 ADO 代码一样。一定要很好地复制它,因为有一些微妙之处不会出错。而且您有义务将您的查询与您的运行时参数连接起来,因为没有提供适当的参数。所以这个方法的所有用户都将使用字符串方法(脆弱、不可测试、sql注入)来构建他们的SQL,并且它们都不会进行单元测试。

            其他答案有相同的错误,只是更多。 SQL 埋在双引号中。 SQL 注入机会散布在各处。尊敬的同行,这绝对是野蛮的行为。如果这是 C# 生成的,那将是一场火焰战争。我们甚至不接受以这种方式生成 HTML,但不知何故它可以用于 SQL。我知道查询参数不是问题的主题,但我们复制并重用我们看到的内容,这里的答案既是模型,也是人们正在做的事情的证明。

            EF 融化了我们的大脑吗? EF 不希望你用 SQL,那何必用 EF 做 SQL。

            想要使用 SQL 与关系数据库对话是成年人的一种健康、正常的冲动。 QueryFirst 展示了如何智能地完成此操作,您的 .sql 文件中的 sql,在您键入时进行验证,并为表和列提供智能感知。 C# 包装器由该工具生成,因此您的查询可以在代码中发现,并为您的输入和结果提供智能感知。端到端强类型,无需担心类型。无需记住列名或其索引。还有许多其他好处......连接的诱惑被移除。也可能错误地处理您的连接。您的所有查询和访问它们的代码都会针对您的开发数据库进行持续集成测试。数据库中的架构更改作为应用程序中的编译错误弹出。我们甚至会在包装器中生成一个自测方法,因此您可以针对现有的生产数据库测试应用程序的新版本,而不必等待电话响起。还有人需要说服吗?

            免责声明:我写的是 QueryFirst :-)

            【讨论】:

              猜你喜欢
              • 2017-02-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-21
              相关资源
              最近更新 更多