简体   繁体   English

EF6:在哪里创建存储过程?

[英]EF6: where to create stored procedures?

I'm using Entity Framework 6 Code First. 我正在使用Entity Framework 6 Code First。 To use My database I need a stored procedure. 要使用我的数据库,我需要一个存储过程。 Whenever the database is created this stored procedure needs to be created. 每当创建数据库时,都需要创建此存储过程。

Edit: the reason for a stored procedure is written at the end of this post. 编辑:存储过程的原因写在这篇文章的结尾。

From Stackoverflow I know how to create a stored procedure and how to call it. 从Stackoverflow我知道如何创建存储过程以及如何调用它。 My question is where do I create it? 我的问题是在哪里创建它?

My first instinct was in DbContext.OnModelCreating . 我的第一个直觉是在DbContext.OnModelCreating中 This function is called whenever the model is created. 每当创建模型时,都会调用此函数。 In this function you'll tell the modelbuilder what the model should look like. 在此功能中,您将告诉模型构建者模型应该是什么样。

Alas, in this function I cannot use the DbContext yet. ,在此功能中,我还不能使用DbContext。 There are functions to override Insert / Update / Delete procedures, but I need a different procedure. 有一些功能可以覆盖“插入/更新/删除”过程,但是我需要一个不同的过程。

I consider to add the function in the Seed function of DropCreateDataBaseIfModelChanges, but that would inhibit users of my DbContext to Seed the database with their own desired data. 我考虑在DropCreateDataBaseIfModelChanges的Seed函数中添加该函数,但这将禁止我的DbContext用户使用其所需的数据为数据库播种。

DbMigrations seems to be developed to migrate an existing database to a newer one. DbMigrations似乎是为了将现有数据库迁移到新数据库而开发的。 Not to be used when the first version of a database is created. 创建数据库的第一个版本时不使用。

So where to create the stored procedures? 那么在哪里创建存储过程呢?


Edit. 编辑。 The reason I need a stored procedure is the following 我需要存储过程的原因如下

My service receives notices that a customer spent money on something today. 我的服务收到有关客户今天花钱购物的通知。 I need to remember the day totals per customer. 我需要记住每个客户的当天总计。

  • If the customer hasn't spent anything on date , which is if no record with (customerId, date) exists, insert a record with the spent value 如果客户在date上还没有花费任何东西, 也就是说 ,如果不存在带有(customerId,date)的记录,则插入一条带有花费值的记录
  • It the customer already spent something on datae , which is if a record with (customerId, date) already exists, add the spent value to the value in the record 如果客户已经在datae上花了一些也就是说 ,如果已经存在带有(customerId,date)的记录,则将花费的值添加到记录中的值

Something like this: 像这样:

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();
        }
    }
}

The problem is that after my Find, someone else might already have Inserted a record. 问题是在“查找”之后,其他人可能已经插入了一条记录。 In that case I should have added the value. 在那种情况下,我应该添加值。 Instead there will be two records. 而是会有两个记录。 Or while I am processing an existing record and adding the value, someone else might process the same existing record. 或者在我处理现有记录并添加值时,其他人可能会处理相同的现有记录。 Therefore the adding of the value should be done inside the database with a statement like 因此,值的添加应在数据库内部使用如下语句完成:

update [CustomerSpends]
Set [SpentValue] = [SpentValue] + @Value
Where [CustomerId] = @CustomerId and [SpentDate] = @SpentDate

2nd edit As * Ivan Yuriev* already mentioned the above could be solved using a transaction. 第二次编辑正如Ivan Yuriev *已经提到的,可以使用事务来解决上述问题。 However I still would have the problem about adding the spends. 但是我仍然会遇到增加支出的问题。

If this would be a 3 step process, like Ivan suggests, it would be like: 如果这是一个三步骤的过程(如Ivan所建议的那样),则它将是:

  • Fetch the existing record 获取现有记录
  • Add spentValue to the total value in the record 将支出值添加到记录的总值中
  • SaveChanges 保存更改

This has the disadvantage that I always need two round trips to the database. 这样做的缺点是我总是需要两次往返数据库。 Besides I get a sequence of customer spends. 此外,我得到了一系列的客户支出。 If any of them fail processing, everything needs to be rolled back. 如果其中任何一个处理失败,则需要回滚所有内容。 Even when using transaction it is possible there are race conditions 即使使用交易,也可能存在竞争条件

The highest Transaction Isolation level (MSDN) is read committed. 最高的事务隔离级别(MSDN)已读取为已提交。

READ COMMITTED Specifies that statements cannot read data that has been modified but not committed by other transactions. READ COMMITTED指定语句不能读取已被其他事务修改但未提交的数据。 This prevents dirty reads. 这样可以防止脏读。 Data can be changed by other transactions between individual statements within the current transaction, resulting in non-repeatable reads or phantom data. 数据可以被当前事务中各个语句之间的其他事务更改,从而导致不可重复的读取或幻像数据。

When using the three step procedure defined above, I fetch record X, with a total spent value of $ 5.00. 当使用上面定义的三步过程时,我获取记录X,总花费值为5.00美元。 While I am adding $ 3 to the total, someone else can also fetch record X, because it has not been modified yet. 当我将总计增加3美元时,其他人也可以获取记录X,因为它尚未被修改。 The other one receives the record with the total of $ 5. After my addition the total value became $ 8. I update the value using SaveChanges and continue with other records. 另一个接收的记录总计为$5。添加后,总值为$8。我使用SaveChanges更新值,并继续其他记录。 After a while I commit my changes. 一段时间后,我提交更改。 The other process who still has the record with $ 5, should add $2, ending with a value of $ 7, while the end result should have been $ 10 另一个仍有$ 5记录的进程应加$ 2,以$ 7结尾,而最终结果应为$ 10

Using transactions can't prevent others to read the data. 使用事务不能阻止其他人读取数据。 Therefore the fetch - add value - update should be done in one SQL statement 因此,获取-添加值-更新应在一条SQL语句中完成

Best way to manage by creating a blank migration and Add your stored procedure in Up method and delete that stored procedure in Down Method . 通过创建空白迁移并在Up方法中添加存储过程并在Down Method中删除该存储过程的最佳管理方式

This will work like. 这将像。

1) Add blank migration by running command on Package Manger Console 1)通过在Package Manger Console上运行命令来添加空白迁移

add-migration 'SomeName' -IgnoreChanges

It will create the migration file 它将创建迁移文件

2) Now Add your stored procedure in Up and Delete the stored procedure in Down 2)现在,在“向上”中添加存储过程,在“向下”中删除存储过程

public partial class SomeName: DbMigration
    {
        public override void Up()
        {
            Sql(@"Add Command For StoredProcedure");

        }

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

Adding Drop in Down method is equally important. 添加Drop in Down方法同样重要。

Nowhere. 无处。 I found code first migrations to be extremely limited and something only people that lack a deep understanding of SQL server concepts and capabilities would feel comfortable using. 我发现代码优先迁移非常有限,只有只有对SQL Server概念和功能缺乏深入了解的人才能使用它。

The way I have gone is: 我走的路是:

  • I maintain a master database and sync the schema to a schema project. 我维护一个主数据库并将架构同步到架构项目。
  • Regularly generate delta scripts which I then manually maintain. 定期生成增量脚本,然后由我手动维护。
  • I have a library that applies delta scripts as needed based on a version number of the database which is stored in an extended property. 我有一个库,该库根据扩展属性中存储的数据库的版本号,根据需要应用增量脚本。

Reasons not to use migrations are simple - you end up having to submit way too many SQL scripts anyway. 不使用迁移的原因很简单-无论如何,您最终不得不提交太多的SQL脚本。 Migrations do not even handle trivial cases such as proper fully configured indices (filtered indices), have no idea of stored procedures, triggers and views, are unable to deal with partitioned tables, are unable to deal efficiently with data migrations that may require temporary tables to store data while the table layout is changed. 迁移甚至无法处理琐碎的情况,例如正确的完全配置的索引(过滤的索引),不了解存储过程,触发器和视图,无法处理分区表,无法有效地处理可能需要临时表的数据迁移在表布局更改时存储数据。 Because I do not deal with trivial databases I require nearly all of those features pretty much daily. 因为我不处理琐碎的数据库,所以几乎每天都需要几乎所有这些功能。

Telling the full truth - I never found code first even an efficient approach. 说出全部真相-我从来没有找到过代码甚至是一种有效的方法。 It is way too error prone. 太容易出错了。 The only thing worse is db first with EF tools - mostly because the edmx designer is as rotten as it gets, totally unable to deal with updates. 更糟糕的是,db首先使用EF工具-主要是因为edmx设计器变得越来越烂,完全无法处理更新。 Third party editors are available, though, and they WORK. 但是可以使用第三方编辑器,并且它们可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM