ይህ ጽሑፍ በ EF 8/ASP.NET8 ውስጥ የተለመዱ ችግሮችን ለመፍታት ከፊል C # ክፍሎችን ለመጠቀም ብዙ ቴክኒኮችን ያሳያል።
ማጠቃለያ፡ በ EF 8 - የውሂብ ጎታ በመጀመሪያ አቀራረብ የተፈጠሩት የ EF ክፍሎች ሞዴሉ በሚታደስበት ጊዜ ስለሚፃፉ ከተጨማሪ ተግባራት ጋር በቀጥታ ሊራዘም አይችልም. ይህንን ለማሸነፍ ከፊል C # ክፍሎችን መጠቀም እንችላለን። ይህ ጽሑፍ በ EF/ASP.NET አካባቢ ውስጥ ተግባራዊነትን ለማራዘም ጠቃሚ ዘዴዎችን ያቀርባል።
በእኔ C#/ASP.NET 8 MVC ፕሮጄክት፣የ Entity Framework Core Database First አካሄድን እየተጠቀምኩ ነው። ይህ አስፈላጊ ነው ምክንያቱም በተለያዩ ቴክኖሎጂዎች ላይ ያሉ በርካታ አፕሊኬሽኖች በተመሳሳይ የSQL አገልጋይ ዳታቤዝ ላይ ስለሚመሰረቱ። ከመረጃ ቋቱ ሞዴል ለማመንጨት EFCorePowerToolsን እጠቀማለሁ።
በመረጃ ቋቱ ንድፍ ላይ ለውጦችን ለማንፀባረቅ የተፈጠረው የኢኤፍ ሞዴል መዘመን ሲያስፈልግ ጉዳዩ ይነሳል። የመነጩ የ EF ህጋዊ አካላት ክፍሎች ስለሚገለበጡ በእነሱ ላይ የተደረጉ ማሻሻያዎች ጠፍተዋል። ይህ ችግር ነው, ምክንያቱም አንዳንድ ጊዜ, በመተግበሪያው ውስጥ ጥቅም ላይ የሚውሉ የ EF አካላትን ማራዘም አለብን.
ይህንን ችግር ለመፍታት ከፊል C # ክፍሎችን በሚያካትቱ ዘዴዎች እተማመናለሁ, ይህም ከዚህ በታች ይብራራል.
በተለመደው የC#/EF/ASP.NET 8 MVC መተግበሪያ፣ ሁኔታው የሚከተለውን ኮድ ሊመስል ይችላል።
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical class generated by EF Core Power Tools //in EF-Database-First approach // <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated> [PrimaryKey("Id")] public partial class Customer { //Customer-partial-class-1 [Key] [StringLength(15)] public string? Id { get; set; } [StringLength(15)] public string? NAME { get; set; } public short? Language { get; set; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical model calls for ASP.NET MVC public class CustomerEdit_ViewModel { //model public string? Id { get; set; } = null; //view model // this is our Customer Entity from EF Core public Customer? Customer1 { get; set; } = null; //this is flag for submit button public bool IsSubmit { get; set; } = false; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical controller for ASP.NET MVC public class CustomersController : Controller { // some Controller code here public async Task<ActionResult> CustomerEdit(CustomerEdit_ViewModel model) { if (model.IsSubmit) { // Model validation is done during model binding // we have to check if model is valid if (ModelState.IsValid) { if (model.Customer1 != null) { //we update existing customer in database //redirect to the list of customers } } else { // we go for presentation of validation errors ModelState.AddModelError("", "PleaseCorrectAllErrors"); } } else { ModelState.Clear(); //go for presentation of original data if (model.Id != null) { //get Customer by Id from database } } return View("CustomerEdit", model); } }
እዚህ፣ ደንበኛ-ከፊል-ክፍል-1 በ EF (ከመረጃ ቋቱ በተገላቢጦሽ ምህንድስና) የተፈጠረ ክፍል ነው። ከመረጃ ቋት ገደቦች ጋር የሚዛመዱ አንዳንድ የማረጋገጫ ባህሪያትን ያካትታል። ይህ ክፍል አብዛኛው ጊዜ በሞዴል ክፍል ውስጥ (ለምሳሌ, CustomerEdit_ViewModel ) ጥቅም ላይ ይውላል, የማረጋገጫ ባህሪያት በአንድ ድርጊት ወይም ዘዴ (ለምሳሌ, CustomerEdit ).
በተፈጠረው ክፍል ውስጥ ንብረቶችን ማከል ከፈለግን ደንበኛ-ከፊል-ክፍል-1ን በቀጥታ ማሻሻል አንችልም ምክንያቱም ይህን ማድረጉ ለውጦቹ እንዲገለበጡ ስለሚያደርግ ነው። በምትኩ፣ ደንበኛ-ከፊል-ክፍል-2 ን መፍጠር እና ብጁ ንብረቶቻችንን እዚያ ማከል እንችላለን። EF እነዚህን ንብረቶች በአምሳያው ውስጥ እንዳያካትት ለመከላከል፣ [የማይታፕ ካርታ] ባህሪን መጠቀም አለብን።
አንድ ምሳሌ ይኸውና፡-
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical class generated by EF Core Power Tools //in EF-Database-First approach // <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated> [PrimaryKey("Id")] public partial class Customer { //Customer-partial-class-1 [Key] [StringLength(15)] public string? Id { get; set; } [StringLength(15)] public string? NAME { get; set; } public short? Language { get; set; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is our partial class that extends our generated class //and is not overwritten by EF Core Power Tools //we use it to add some additional properties public partial class Customer { //Customer-partial-class-2 [NotMapped] public int NumberOfCreditCards { get; set; } = 0; [NotMapped] public string? LanguageString { get { string? result = "Unknown"; if (Language == 1) { result = "English"; } else if (Language == 2) { result = "German"; } return result; } } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical model calls for ASP.NET MVC public class CustomerEdit_ViewModel { //model public string? Id { get; set; } = null; //view model // this is our Customer Entity from EF Core public Customer? Customer1 { get; set; } = null; //this is flag for submit button public bool IsSubmit { get; set; } = false; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical controller for ASP.NET MVC public class CustomersController : Controller { // some Controller code here //............. //this is typical action for editing customer public async Task<ActionResult> CustomerEdit(CustomerEdit_ViewModel model) { if (model.IsSubmit) { // Model validation is done during model binding // we have to check if model is valid if (ModelState.IsValid) { if (model.Customer1 != null) { //we update existing customer in database //redirect to the list of customers } } else { // we go for presentation of validation errors ModelState.AddModelError("", "PleaseCorrectAllErrors"); } } else { ModelState.Clear(); //go for presentation of original data if (model.Id != null) { //get Customer by Id from database } } return View("CustomerEdit", model); } }
ኮዱ, ዝርዝር አስተያየቶች ያሉት, እራሱን የሚገልጽ መሆን አለበት.
አንዳንድ ጊዜ፣ በ EF ውስጥ በራስ ሰር የመነጩ የማረጋገጫ ባህሪያት በቂ አይደሉም፣ እና ብጁ የማረጋገጫ ደንቦችን ማከል አለብን። በድጋሚ, ከፊል ክፍሎች ወደ ማዳን ይመጣሉ. ከዚህ በታች አንድ ምሳሌ ነው።
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical class generated by EF Core Power Tools //in EF-Database-First approach // <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated> [PrimaryKey("Id")] public partial class Customer { //Customer-partial-class-1 [Key] [StringLength(15)] public string? Id { get; set; } [StringLength(15)] public string? NAME { get; set; } public short? Language { get; set; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is our partial class that extends our generated class //and is not overwritten by EF Core Power Tools //we use it to add some additional properties //and do some additional validation [MetadataType(typeof(Customer_MetaData))] public partial class Customer { //Customer-partial-class-2 public Customer() { TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider( typeof(Customer), typeof(Customer_MetaData)), typeof(Customer)); } [NotMapped] public int NumberOfCreditCards { get; set; } = 0; [NotMapped] public string? LanguageString { get { string? result = "Unknown"; if (Language == 1) { result = "English"; } else if (Language == 2) { result = "German"; } return result; } } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is our metadata class for our partial class //purpose of this class is to add validation attributes to our partial class //in addition to those that are already in generated class public class Customer_MetaData { //main trick here is that we are adding more validation attributes //in addition to those in generated class [Required] [MinLength(5)] public string? Id { get; set; } = string.Empty; //main trick here is that we are adding more validation attributes //in addition to those in generated class [Required] [MinLength(3)] public string? NAME { get; set; } = string.Empty; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical model calls for ASP.NET MVC public class CustomerEdit_ViewModel { //model public string? Id { get; set; } = null; //view model // this is our Customer Entity from EF Core public Customer? Customer1 { get; set; } = null; //this is flag for submit button public bool IsSubmit { get; set; } = false; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is utility class for validation public class ValidationUtil { /// <summary> /// Validates the specified model object against custom validation rules. /// </summary> /// <param name="model">The model object to validate.</param> /// <param name="modelState">The ModelStateDictionary to store validation errors.</param> /// <param name="logger">The logger to log errors.</param> /// <param name="prefix">An optional prefix for error keys in the ModelStateDictionary.</param> /// <returns>True if validation is successful; otherwise, false.</returns> /// <exception cref="ArgumentNullException">Thrown when the model is null.</exception> public static bool ValidateModelForCustomRules( object model, ModelStateDictionary modelState, ILogger? logger, string? prefix = null) { bool validationSuccessful = false; try { if (model == null) { throw new ArgumentNullException(nameof(model)); } else { var validationContext = new ValidationContext(model); var validationResults = new List<ValidationResult>(); Validator.TryValidateObject(model, validationContext, validationResults, true); foreach (var result in validationResults) { foreach (var memberName in result.MemberNames) { string key = string.IsNullOrEmpty(prefix) ? memberName : $"{prefix}.{memberName}"; modelState.AddModelError(key, result.ErrorMessage ?? "Error"); } } //Go recursively into depth for all properties of the model object that are objects themselves //we must go manually recursively into depth because API Validator.TryValidateObject does validation //only for class properties on first level foreach (var property in model.GetType().GetProperties()) { if (property.PropertyType.IsClass && property.PropertyType != typeof(string)) { var propertyValue = property.GetValue(model); if (propertyValue != null) { validationSuccessful &= ValidateModelForCustomRules(propertyValue, modelState, logger, property.Name); } } } } } catch (Exception ex) { string methodName = $"Type: {System.Reflection.MethodBase.GetCurrentMethod()?.DeclaringType?.FullName}, " + $"Method: ValidateModel; "; logger?.LogError(ex, methodName); validationSuccessful = false; } return validationSuccessful; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //this is typical controller for ASP.NET MVC public class CustomersController : Controller { // some Controller code here //............. //this is typical action for editing customer public async Task<ActionResult> CustomerEdit(CustomerEdit_ViewModel model) { if (model.IsSubmit) { // Model validation is done during model binding but we need more //validating for custom validation rules ValidationUtil.ValidateModelForCustomRules(model, ModelState, null); // we have to check if model is valid if (ModelState.IsValid) { if (model.Customer1 != null) { //we update existing customer in database //redirect to the list of customers } } else { // we go for presentation of validation errors ModelState.AddModelError("", "PleaseCorrectAllErrors"); } } else { ModelState.Clear(); //go for presentation of original data if (model.Id != null) { //get Customer by Id from database } } return View("CustomerEdit", model); } }
እንደሚመለከቱት የደንበኛ-ከፊል-ክፍል-2ን አሻሽለናል እና የደንበኛ_ሜታዳታ ክፍል አክለናል። እዚህ ያለው አላማ ቢያንስ 3 ቁምፊዎችን የሚፈልግ ለNAME ንብረት ተጨማሪ ማረጋገጫን ማከል ነው።
በ ASP.NET MVC ውስጥ፣ የስህተት መልዕክቶችን ለማረጋገጥ እና ለማውጣት ModelStateን መጠቀም እንችላለን። እንዲሁም ብጁ ማረጋገጫን በእጅ ለማስነሳት የፍጆታ ዘዴን ValidationUtil.ValidateModelForCustomRules መጠቀም እንዳለብን ልብ ይበሉ።
ይህንን ዘዴ ለመረዳት ኮዱ እና አስተያየቶች ሁሉንም አስፈላጊ ዝርዝሮች ማቅረብ አለባቸው.
በእኔ C#/EF/ASP.NET 8 MVC አፕሊኬሽን ውስጥ የ EF-የተፈጠሩ ክፍሎችን ተግባራዊነት ለማራዘም ከላይ የተጠቀሱትን ቴክኒኮች በከፊል C # ክፍሎች እጠቀማለሁ። እነዚህ ዘዴዎች የተለመዱ ሁኔታዎችን ያቃልላሉ፣ ይህም ኮዱን ይበልጥ አጭር እና ለማቆየት ቀላል ያደርገዋል።