如何解决C#实体框架:批量扩展输入内存问题
我目前正在使用EF扩展程序。我不明白的一件事,“它应该有助于提高性能”
但是,将一百万条以上的记录放入List变量中,本身就是内存问题。 因此,如果要更新百万条记录而又不将所有内容保存在内存中,那么如何有效地做到这一点?
我们应该使用library(shiny)
library(shinyjs)
#Define ui
first_module_ui <- function(id) {
ns <- NS(id)
tagList(numericInput(
inputId = ns("first_input"),label = "First input:",value = 1
))
}
#Define server logic
first_module_server <- function(input,output,session) {
return(input)
}
#Define ui
second_module_ui <- function(id) {
ns <- NS(id)
tagList(uiOutput(outputId = ns("second_input")),numericInput(
inputId = ns("additional_input"),label = "Additional input",value = 5
))
}
#Define server logic
second_module_server <- function(input,session,first_module_res) {
ns <- session$ns
second_input <- reactive({
first_module_res$first_input + 1
})
output$second_input <- renderUI({
disabled(textInput(
inputId = ns("second_input"),label = "Second input:",value = second_input()
))
})
return(list(
second_input = reactive({second_input()}),additional_input = reactive({input$additional_input})
))
}
#Define ui
third_module_ui <- function(id) {
ns <- NS(id)
tagList(uiOutput(outputId = ns("third_input")),verbatimTextOutput(outputId = ns("fourth_output")))
}
#Define server logic
third_module_server <- function(input,second_module_res) {
ns <- session$ns
third_input <- reactive({
second_module_res$second_input() + 1
})
output$third_input <- renderUI({
disabled(textInput(
inputId = ns("third_input"),label = "Third input:",value = third_input()
))
})
output$fourth_output <- renderPrint({
second_module_res$additional_input()
})
}
# Define UI
ui <- fluidPage(
useShinyjs(),# Application title
titlePanel("Demo"),# Sidebar
sidebarLayout(
sidebarPanel(
first_module_ui("first")
),mainPanel(
second_module_ui("second"),third_module_ui("third")
)
)
)
# Define server logic
server <- function(input,session) {
first_module_res <- callModule(first_module_server,"first")
second_module_res <- callModule(second_module_server,"second",first_module_res)
callModule(third_module_server,"third",second_module_res)
}
# Run the application
shinyApp(ui = ui,server = server)
并分批更新10,000吗? EFExtensions BulkUpdate是否具有任何本机功能来支持此功能?
示例:
for loop
资源:
https://entityframework-extensions.net/bulk-update
解决方法
这实际上不是EF的目的。 EF的数据库交互从记录对象开始,然后从那里开始。如果未对实体进行更改跟踪(因此未加载),则EF无法生成部分UPDATE(即不覆盖所有内容),并且类似地,它不能基于条件而不是键来删除记录。
对于条件更新/删除逻辑,例如
,没有等效的EF(不加载所有这些记录)UPDATE People
SET FirstName = 'Bob'
WHERE FirstName = 'Robert'
或
DELETE FROM People
WHERE FirstName = 'Robert'
使用EF方法执行此操作将要求您加载所有这些实体,只是将它们发送回(更新或删除)到数据库中,这已经浪费了带宽和性能。
我在这里找到的最佳解决方案是绕过EF的LINQ友好方法,而是自己执行原始SQL。仍然可以使用EF上下文来完成此操作。
using (var ctx = new MyContext())
{
string updateCommand = "UPDATE People SET FirstName = 'Bob' WHERE FirstName = 'Robert'";
int noOfRowsUpdated = ctx.Database.ExecuteSqlCommand(updateCommand);
string deleteCommand = "DELETE FROM People WHERE FirstName = 'Robert'";
int noOfRowsDeleted = ctx.Database.ExecuteSqlCommand(deleteCommand);
}
更多信息here。当然,别忘了在相关情况下防止SQL注入。
运行原始SQL的特定语法可能因EF / EF Core版本不同而异,但据我所知,所有版本都允许您执行原始SQL。
我无法对EF Extensions或BulkUpdate的性能发表任何评论,也不会从它们那里购买。
根据他们的文档,他们似乎没有带有正确签名的方法来允许条件更新/删除逻辑。
-
BulkUpdate
似乎不允许您输入可以优化此条件的逻辑条件(UPDATE命令中的WHERE)。 -
BulkDelete
仍然具有BatchSize
设置,这表明它们仍一次处理一个记录(我想每批次),并且不使用带有条件的单个DELETE查询(WHERE子句)。
根据问题中的预期代码,EF Extensions并没有真正为您提供所需的内容。在数据库上直接执行原始SQL会更高效,更便宜,因为这避免了EF加载其实体的需要。
更新
我可能会更正,如条件here所示,有一些 支持条件更新逻辑。但是,我不清楚该示例是否仍将所有内容加载到内存中,并且如果您已经将所有内容都加载到内存中,那么该条件WHERE逻辑的目的是什么(为什么不使用内存中的LINQ?)
但是,即使这种方法在不加载实体的情况下仍然有效:
- 受更大限制(与允许任何有效布尔值的SQL相比,SQL只允许进行相等性检查),
- 相对复杂(我不喜欢他们的语法,也许那是主观的)
- 价格更高(仍然是付费图书馆)
与滚动您自己的原始SQL查询相比。我仍然建议在这里滚动自己的原始SQL,但这只是我的意见。
,我发现了使用类似查询条件的批量更新的“适当” EF扩展方式:
var productUpdate = _dbContext.Set<Product>()
.Where(x => x.ProductType == 'Electronics')
.UpdateFromQuery( x => new Product { ProductBrand = "ABC Company" });
这将导致生成正确的SQL UPDATE ... SET ... WHERE
,而无需按照the documentation首先加载实体:
为什么
UpdateFromQuery
比SaveChanges
,BulkSaveChanges
和BulkUpdate
快?
UpdateFromQuery
直接在SQL中执行一条语句,例如UPDATE [TableName] SET [SetColumnsAndValues] WHERE [Key]
。其他操作通常需要一次或多次数据库往返,这会使性能降低。
您可以在BulkUpdate
的示例中改编此dotnet fiddle example上的工作语法。
其他注意事项
-
不幸的是,没有提及此操作的批处理操作。
-
在进行像这样的大更新之前,可能值得考虑停用此列上可能具有的索引,然后再重建它们。如果您有很多的话,这尤其有用。
-
请注意
Where
中的条件,如果EF无法将其转换为SQL,则将在客户端执行,这意味着“通常”可怕的往返行程“加载-更改内存-更新”
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。