我应该将此方法的查询转换为存储过程吗? [关闭]
Posted
技术标签:
【中文标题】我应该将此方法的查询转换为存储过程吗? [关闭]【英文标题】:Should I convert this method's queries to Stored Procedures? [closed] 【发布时间】:2021-10-20 07:29:48 【问题描述】:在我的工作中,其他开发人员花费了大量时间将他们的 sql 查询转换为存储过程。就个人而言,我认为这是有道理的,因为其中很多查询都很复杂并且连接了许多表。另一方面,我还没有写过这么复杂的查询,所以我认为坚持使用 EF/Linq 就可以了。然而,在我最近的公关中,我的领导强调了我的一种方法,并说它应该转换为存储过程。我不同意,因为它非常简单,但从技术上讲,他是我领导的,所以我希望其他人关注它,也许他是对的。这是有问题的方法:
public static List<FormFieldPropertyHistoryViewModel> GetFieldPropertyHistory(int? formFieldId)
List<FormFieldPropertyHistoryViewModel> history = new List<FormFieldPropertyHistoryViewModel>();
List<dbo_FormFields_CT> fields = new List<dbo_FormFields_CT>();
using (var ctx = new Entities())
fields = ctx.dbo_FormFields_CT.Where(f => f.ID == formFieldId).ToList();
foreach (var row in fields)
var ffhvm = new FormFieldPropertyHistoryViewModel();
switch (row.FieldType)
case "TEXTBOX":
using (var ctx = new Entities())
var textboxHistory = new FormFieldTextBoxPropertyHistoryViewModel();
var textboxfield = ctx.dbo_FormFieldsTextBox_CT.Where(f => f.FormFieldsID == formFieldId && f.C___operation == row.C___operation && f.C___start_lsn == row.C___start_lsn).FirstOrDefault();
textboxHistory.DateEdited = row.DateAdded;
textboxHistory.EditedBy = row.CreatedBy;
textboxHistory.Label = row.Label;
textboxHistory.IsRequired = row.IsRequired;
textboxHistory.IsSystemField = row.IsSystemField;
textboxHistory.IsAssessmentField = row.IsAssessmentField;
textboxHistory.Hint = row.Hint;
textboxHistory.HelpText = row.HelpText;
textboxHistory.UniqueField = row.UniqueField;
textboxHistory.RegexField = row.RegexField;
if (textboxfield != null)
textboxHistory.MaxCharacters = textboxfield.MaxCharacters;
textboxHistory.IsPassword = row.IsPassword;
textboxHistory.IsWikiSearch = row.IsWikiSearch;
history.Add(textboxHistory);
break;
case "TEXTAREA":
using (var ctx = new Entities())
var textareaHistory = new FormFieldTextAreaPropertyHistoryViewModel();
var textboxfield = ctx.dbo_FormFieldsTextBox_CT.Where(f => f.FormFieldsID == formFieldId && f.C___operation == row.C___operation && f.C___start_lsn == row.C___start_lsn).FirstOrDefault();
textareaHistory.DateEdited = row.DateAdded;
textareaHistory.EditedBy = row.CreatedBy;
textareaHistory.Label = row.Label;
textareaHistory.IsRequired = row.IsRequired;
textareaHistory.IsSystemField = row.IsSystemField;
textareaHistory.IsAssessmentField = row.IsAssessmentField;
textareaHistory.HelpText = row.HelpText;
textareaHistory.RegexField = row.RegexField;
if (textboxfield != null)
textareaHistory.MaxCharacters = textboxfield.MaxCharacters;
textareaHistory.IsEditable = textboxfield.isEditable;
textareaHistory.IsRichTextBox = textboxfield.isRichTextBox;
history.Add(textareaHistory);
break;
case "CHECKBOX":
var checkboxHistory = new FormFieldCheckboxPropertyHistoryViewModel();
checkboxHistory.DateEdited = row.DateAdded;
checkboxHistory.EditedBy = row.CreatedBy;
checkboxHistory.Label = row.Label;
checkboxHistory.IsRequired = row.IsRequired;
checkboxHistory.IsSystemField = row.IsSystemField;
checkboxHistory.IsAssessmentField = row.IsAssessmentField;
checkboxHistory.HelpText = row.HelpText;
history.Add(checkboxHistory);
break;
case "DROPDOWNLIST":
var dropdownHistory = new FormFieldDropDownPropertyHistoryViewModel();
dropdownHistory.DateEdited = row.DateAdded;
dropdownHistory.EditedBy = row.CreatedBy;
dropdownHistory.Label = row.Label;
dropdownHistory.IsRequired = row.IsRequired;
dropdownHistory.IsSystemField = row.IsSystemField;
dropdownHistory.IsAssessmentField = row.IsAssessmentField;
dropdownHistory.HelpText = row.HelpText;
dropdownHistory.HoverText = row.HoverText;
dropdownHistory.Options = row.Options;
dropdownHistory.SelectedOption = row.SelectedOption;
dropdownHistory.AllowUserValues = row.AllowUserValues;
dropdownHistory.UniqueField = row.UniqueField;
history.Add(dropdownHistory);
break;
case "RADIOBUTTON":
var radioHistory = new FormFieldRadioPropertyHistoryViewModel();
radioHistory.DateEdited = row.DateAdded;
radioHistory.EditedBy = row.CreatedBy;
radioHistory.Label = row.Label;
radioHistory.IsRequired = row.IsRequired;
radioHistory.IsSystemField = row.IsSystemField;
radioHistory.IsAssessmentField = row.IsAssessmentField;
radioHistory.HelpText = row.HelpText;
radioHistory.Options = row.Options;
radioHistory.SelectedOption = row.SelectedOption;
history.Add(radioHistory);
break;
case "CALCULATEDFIELD":
using (var ctx = new Entities())
var calcFieldHistory = new FormFieldCalculatedPropertyHistoryViewModel();
var calcfield = ctx.dbo_FormFieldsCalculatedField_CT.Where(f => f.FormFieldsID == formFieldId && f.C___operation == row.C___operation && f.C___start_lsn == row.C___start_lsn).FirstOrDefault();
calcFieldHistory.DateEdited = row.DateAdded;
calcFieldHistory.EditedBy = row.CreatedBy;
calcFieldHistory.Label = row.Label;
calcFieldHistory.IsRequired = row.IsRequired;
calcFieldHistory.IsSystemField = row.IsSystemField;
calcFieldHistory.IsAssessmentField = row.IsAssessmentField;
calcFieldHistory.Hint = row.Hint;
calcFieldHistory.HelpText = row.HelpText;
if (calcfield != null)
calcFieldHistory.Formula = calcfield.Formula;
calcFieldHistory.CurrencyType = row.CurrencyType;
calcFieldHistory.TimeZone = row.TimeZone;
history.Add(calcFieldHistory);
break;
case "LOOKUP":
using (var ctx = new Entities())
var lookupFieldHistory = new FormFieldLookupPropertyHistoryViewModel();
var lookupfield = ctx.dbo_FormFieldsLookupList_CT.Where(f => f.FormFieldsID == formFieldId && f.C___operation == row.C___operation && f.C___start_lsn == row.C___start_lsn).FirstOrDefault();
lookupFieldHistory.DateEdited = row.DateAdded;
lookupFieldHistory.EditedBy = row.CreatedBy;
lookupFieldHistory.Label = row.Label;
lookupFieldHistory.IsRequired = row.IsRequired;
lookupFieldHistory.IsSystemField = row.IsSystemField;
lookupFieldHistory.IsAssessmentField = row.IsAssessmentField;
lookupFieldHistory.Hint = row.Hint;
lookupFieldHistory.HelpText = row.HelpText;
lookupFieldHistory.EnableAddNew = row.EnableAddNew;
lookupFieldHistory.UniqueField = row.UniqueField;
if (lookupfield != null)
lookupFieldHistory.LookupList = lookupfield.LookupList;
lookupFieldHistory.LookupColumns = lookupfield.LookupColumns;
lookupFieldHistory.LookupAdditionalColumns = lookupfield.LookupAdditionalColumns;
history.Add(lookupFieldHistory);
break;
case "ADDRESS":
case "PHONE":
var addressHistory = new FormFieldAddressPropertyHistoryViewModel();
addressHistory.DateEdited = row.DateAdded;
addressHistory.EditedBy = row.CreatedBy;
addressHistory.Label = row.Label;
addressHistory.IsRequired = row.IsRequired;
addressHistory.IsSystemField = row.IsSystemField;
addressHistory.IsAssessmentField = row.IsAssessmentField;
addressHistory.HelpText = row.HelpText;
history.Add(addressHistory);
break;
case "EMAIL":
var emailHistory = new FormFieldEmailPropertyHistoryViewModel();
emailHistory.DateEdited = row.DateAdded;
emailHistory.EditedBy = row.CreatedBy;
emailHistory.Label = row.Label;
emailHistory.IsRequired = row.IsRequired;
emailHistory.IsSystemField = row.IsSystemField;
emailHistory.IsAssessmentField = row.IsAssessmentField;
emailHistory.MaxChars = row.MaxChars;
history.Add(emailHistory);
break;
case "DATEPICKER":
case "BIRTHDAYPICKER":
var datepickerHistory = new FormFieldDatePickerPropertyHistoryViewModel();
datepickerHistory.DateEdited = row.DateAdded;
datepickerHistory.EditedBy = row.CreatedBy;
datepickerHistory.Label = row.Label;
datepickerHistory.IsRequired = row.IsRequired;
datepickerHistory.IsSystemField = row.IsSystemField;
datepickerHistory.IsAssessmentField = row.IsAssessmentField;
datepickerHistory.HelpText = row.HelpText;
datepickerHistory.TimeZone = row.TimeZone;
history.Add(datepickerHistory);
break;
case "FULLNAME":
var fullNameHistory = new FormFieldFullnamePropertyHistoryViewModel();
fullNameHistory.DateEdited = row.DateAdded;
fullNameHistory.EditedBy = row.CreatedBy;
fullNameHistory.Label = row.Label;
fullNameHistory.IsRequired = row.IsRequired;
fullNameHistory.IsSystemField = row.IsSystemField;
fullNameHistory.IsAssessmentField = row.IsAssessmentField;
fullNameHistory.HelpText = row.HelpText;
fullNameHistory.UniqueField = row.UniqueField;
history.Add(fullNameHistory);
break;
case "FILEPICKER":
using (var ctx = new Entities())
var fileFieldHistory = new FormFieldFilePropertyHistoryViewModel();
var filefield = ctx.dbo_FormFieldsFileUpload_CT.Where(f => f.FormFieldsID == formFieldId && f.C___operation == row.C___operation && f.C___start_lsn == row.C___start_lsn).FirstOrDefault();
fileFieldHistory.DateEdited = row.DateAdded;
fileFieldHistory.EditedBy = row.CreatedBy;
fileFieldHistory.Label = row.Label;
fileFieldHistory.IsRequired = row.IsRequired;
fileFieldHistory.HelpText = row.HelpText;
if (filefield != null)
fileFieldHistory.AllowedFileExtensions = filefield.AllowedFileExtensions;
fileFieldHistory.MinFileSizeInMB = filefield.MinFileSizeInMB;
fileFieldHistory.MaxFileSizeInMB = filefield.MaxFileSizeInMB;
history.Add(fileFieldHistory);
break;
default:
break;
return history;
【问题讨论】:
忘记触发!开关是代码气味。我会重构它。研究条件多态性。 按照您的首席开发人员所说的去做。在我当前的项目中,没有 EF,一切都是存储过程,即使是极其简单的东西。这是主要开发人员的选择,您应该与项目的其余部分保持一致。 上面没有 SQL 或存储过程。我们怎么知道转换是否正常...? 我建议问问他们为什么。他们可能有充分的理由,也可能没有,也可能有不好的理由。在最后两种情况下,他们可能愿意讨论存储过程的优缺点,或者他们可能只是说(有效地)“这样做”。所以:我们不能回答“我应该”的问题。您大概可以,这样做可能是一个好主意,也可能不是一个好主意。是否使用存储过程在很大程度上取决于上下文决定,我们缺乏您的上下文。 【参考方案1】:这里有一些考虑因素,无论是赞成还是反对你的立场。
首先,
我不同意,因为它非常简单
这段代码绝非简单。它迫切需要重构,因为它非常臃肿且几乎无法维护。它太单一了,在它之上是交换机分支和深度嵌套。
这是教科书式的 OCP 违规行为,迫切需要将其组成分支分成单独的组件。
无论是否存储过程,此代码都不应通过任何合理的代码审查。
其次,
在我的工作中,其他开发人员花费了大量时间将他们的 sql 查询转换为存储过程。
我通常认为从 EF 迁移到存储过程是朝着错误的方向发展。虽然存在(罕见的)边缘情况,其中存储的过程比 EF 的代码内查询语法更适合特定用例,但我很难找到任何你应该覆盖的情况转移到存储过程,而不是使用 EF 并偶尔依赖相关的存储过程。
如果所有开发人员都将他们的查询转换为存储过程,这听起来很好超出了一个合理的边缘特殊用例,并且正在钻研建筑考古学领域。
第三,
另一方面,我还没有写过这么复杂的查询,所以我认为坚持使用 EF/Linq 就可以了。
尽管无论如何我都不支持存储过程,但你也不应该流氓。一个一致但陈旧的代码库仍然比一个包含不同方法和实现的代码库更好,每个开发人员都做自己的事情。
将这些考虑因素提炼成可能的最佳建议:
始终确保开发人员之间的一致性。无论做出何种选择。 虽然存储过程并非不可能实现,但它们至少是一种过时的方法。肯定有与首席开发人员进行讨论的空间,以重新评估存储过程是否是正确的方法。 但是,重新评估可能已经发生,而您根本没有参与决策过程。 根据所写的问题,我无法判断您的首席开发人员是否进行了糟糕的盲注,或者他们是否真正评估了他们的选择,而您只是没有在问题中提供完整的情况. 我不想刻薄,根据您提供的代码并称其很简单,我推断您是一名初级开发人员,与您的首席开发人员以及您的一些人相比,您不太可能成为具有同等重要性的声音合作伙伴。我非常怀疑您的意见是否会影响任何人,除非您提出一些非主观的具体证据。 如果所有其他方法都失败了,仍然值得与您的首席开发人员交谈以至少了解他们的推理。不是作为争论他们为什么错的切入点,而是了解他们来自哪里以及他们为什么选择这种方法。即使您无法改变他们的想法,这也是一个很好的学习机会,也许在您获得某种发言权的未来项目中,您将更能够做出平衡的判断。【讨论】:
【参考方案2】:在你的 DbContext 上放置一个方法来封装这个查询并使用它。例如
public IList<FormField> GetFormFieldsById( int formFieldId )
var fields = this.dbo_FormFields_CT.Where(f => f.ID == formFieldId).ToList();
return fields;
然后,如果您、您的主管或其他开发人员想要实现一个存储过程来保存此逻辑,则您的代码不必更改。
但您不必跳到其他工具并开始用其他语言编写查询来完成此功能。
【讨论】:
“完成这个功能”并不是这里的全部目标。代码库的一致性是“它有效”之外的一个重要因素,OP 提到他们的同事已经普遍转向存储过程。无论如何,我都不喜欢存储过程,但我更不喜欢带有拼凑实现和样式的零散代码库。 我的意思是你可以两者兼得。从封装在 DbContext 中的 LINQ 查询开始,然后根据需要将其替换为存储过程。这也使其他人能够创建存储过程。 最后一段似乎非常支持一种方法而不是另一种方法。这表明您不应该必须转移到存储过程。我并不完全不同意,但值得注意的是开发团队内部的一致性。以上是关于我应该将此方法的查询转换为存储过程吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
将 SQL 查询转换为 PL/SQL 可以提高 Oracle 12c 中的性能吗? [关闭]
将 SQL Server 存储过程转换为 Oracle 过程以从表中查询