EF6:创建存储过程的位置?

时间:2016-05-24 14:27:24

标签: c# entity-framework stored-procedures

我正在使用Entity Framework 6 Code First。要使用我的数据库,我需要一个存储过程。无论何时创建数据库,都需要创建此存储过程。

  

编辑:存储过程的原因写在本文末尾。

从Stackoverflow我知道如何创建存储过程以及如何调用它。我的问题是我在哪里创建它?

我的第一直觉是 DbContext.OnModelCreating 。无论何时创建模型,都会调用此函数。在这个函数中,您将告诉模型构建器模型应该是什么样的。

唉,在这个函数中我还不能使用DbContext。有一些函数可以覆盖插入/更新/删除过程,但我需要一个不同的过程。

我考虑在DropCreateDataBaseIfModelChanges的种子函数中添加该函数,但这会阻止我的DbContext用户使用他们自己想要的数据对数据库进行种子化。

似乎开发了

DbMigrations 以将现有数据库迁移到更新的数据库。创建数据库的第一个版本时不使用。

那么在哪里创建存储过程?

修改。我需要存储过程的原因如下

我的服务收到客户今天在某事上花钱的通知。我需要记住每个客户的总日数。

  • 如果客户未在 date 上花费任何费用,即如果没有(customerId,date)记录,则插入带有已用值的记录
  • 客户已经在 datae 上花了一些东西,如果已经存在(customerId,date)的记录,则将花费的值添加到记录中的值

这样的事情:

public void InsertOrAdd(int customerId, DateTime date, decimal value)
{
    using (var dbContext = CreateContext())
    {
        var retrievedRecord = dbContext.Find(...)
        if (retrievedRecord == null)
        {
            InsertRecord(customerId, date, value);
        }
        else
        {
            retrievedRecord.Value += value;
            dbContext.SaveChanges();
        }
    }
}

问题是,在我查找之后,其他人可能已经插入了记录。在那种情况下,我应该添加值。相反,会有两个记录。或者在处理现有记录并添加值时,其他人可能会处理相同的现有记录。因此,应该使用类似

的语句在数据库内部添加值
update [CustomerSpends]
Set [SpentValue] = [SpentValue] + @Value
Where [CustomerId] = @CustomerId and [SpentDate] = @SpentDate

第二次修改 正如* Ivan Yuriev *已经提到的,上述问题可以通过交易来解决。但是我仍然会有关于添加花费的问题。

如果这是一个3步骤的过程,就像Ivan建议的那样,那就像是:

  • 获取现有记录
  • 将spentValue添加到记录
  • 中的总值
  • 的SaveChanges

这样做的缺点是我总是需要两次往返数据库。除此之外,我得到了一系列客户支出。如果其中任何一个处理失败,则需要回滚所有内容。即使使用交易,也有可能存在竞争条件

最高Transaction Isolation level (MSDN)已读取已提交。

  

READ COMMITTED   指定语句无法读取已修改但未由其他事务提交的数据。这可以防止脏读。当前事务中各个语句之间的其他事务可以更改数据,从而导致不可重复的读取或幻像数据。

当使用上面定义的三步程序时,我获取记录X,总消耗值为$ 5.00。虽然我总共增加了3美元,但其他人也可以获取记录X,因为它尚未被修改。另一个收到总额为5美元的记录。加入后,总价值变为8美元。我使用SaveChanges更新值并继续其他记录。过了一会儿,我提交了我的更改。另一个仍然有5美元记录的流程应该加2美元,结果价值7美元,而最终结果应该是10美元

使用交易无法阻止他人读取数据。因此,fetch - add值 - 更新应该在一个SQL语句中完成

2 个答案:

答案 0 :(得分:1)

通过创建空白迁移进行管理的最佳方式,并在向上方法中添加存储过程,并在向下方法中删除该存储过程。

这就像。

1)通过在Package Manger Console上运行命令

添加空白迁移
add-migration 'SomeName' -IgnoreChanges

它将创建迁移文件

2)现在在Up中添加存储过程并在Down

中删除存储过程
public partial class SomeName: DbMigration
    {
        public override void Up()
        {
            Sql(@"Add Command For StoredProcedure");

        }

        public override void Down()
        {
            Sql(@"Drop Command for Stored Procedure")
        }
    } 

添加Drop in Down方法同样重要。

答案 1 :(得分:1)

无处。我发现代码首次迁移非常有限,只有那些对SQL服务器概念和功能缺乏深刻理解的人才会觉得很舒服。

我走的路是:

  • 我维护一个主数据库并将架构同步到架构项目。
  • 定期生成delta脚本,然后我手动维护。
  • 我有一个库,根据存储在扩展属性中的数据库的版本号,根据需要应用delta脚本。

不使用迁移的原因很简单 - 最终你不得不提交过多的SQL脚本。迁移甚至不处理琐碎的情况,例如正确完全配置的索引(过滤索引),不知道存储过程,触发器和视图,无法处理分区表,无法有效处理可能需要临时表的数据迁移在更改表格布局时存储数据。因为我不处理琐碎的数据库,所以我每天都需要几乎所有这些功能。

告诉全部真相 - 我从未发现代码甚至是一种有效的方法。这太容易出错了。唯一更糟的是db首先使用EF工具 - 主要是因为edmx设计师虽然变得腐烂,完全无法处理更新。但是,可以使用第三方编辑,他们可以工作。