Entity Framework missing FAQ Part 1:
- 1. Database First
- 1.1. Традиційні DB First без моделера Visual Studio
- 1.2. Вам допоможе Nuget.ORG
- 1.3. ObjectContext vs DbContext
- 1.4. Поширення EF
- 1.5. Довідники EF
- 2. Model First
- 2.1 Переваги Model First над Database First
- 2.2 Приклад
- 2.3 Схема моделі вбудована у ресурс DLL
- 2.4 Міграція (Package console/CMD utility/site code)
- 2.5 Публікація проекту з EF
- 2.6 Профайлер трансляции EF з Linq у SQL та EF Retry Policy (повний код проєкту)
- 2.7 Альтернативи мікрософтовському ModelFirst
Entity Framework missing FAQ (Part 2).
- 3. Code First
- 3.1. Site with Project and without project (порівняння типів проєктів).
- 3.2. Стартовий MVC-project Contoso University in VB.
- 3.3. Attributes and Fluent API.
- 3.4 Перелік атрибутів Data Annotations.
- 3.5 Scaffold template and custom scaffold template.
- 3.6 Close look to controller code
- 3.7 Виготовлення власних Extension-хелперов
- 3.8. Store data in ViewState/ViewBag/ViewData/TempData
3.1. Site with Project and without project (порівняння типів проєктів).
Це, друзі, продовження продовження першої частини моєї інтерпретації всесвітньо відомого прикладу ContosoUniversity. Я почну його с того, що спробую зробити проєкт у так званій проєктній архітектурі, тому що так зробили автори цього прикладу. Ну взагалі, ASP NET сайти можливо робити двома засобами - у проєктній та безпроєктній архітектурі. Особисто я, якщо це хоч якось можливо - я все роблю лише в безпроєктній, тому що код можно модифікувати без перезапуску проєкту. Це для мене головне, але багато людей бачить якісь переваги проєктної архітектури, я ці дурниці повторювати не буду. Тобто, ви можете створити сайт (ми поки що не говоримо про сайти для Linux на CORE або на XIMARIN, лише про ASP NET сайти для Windows) - їх можна зробити двома засобами. Або як окремий проєкт, або проєкт вбудований у солушен.
Приклад першої частини я зробив як безпроєктний. У цьому випадку солушен буде виглядати як планетка, окремого файла PRJ не буде, також у папці проєкту не буде вузла MyProject. Повних Property як у звичайному Class Library проєкті теж не буде (та це й непотрібно для сайту)
У проєктній архітектурі, секція проєкту буде присутня в окремому PRJ-файліку, буде присутні повні property від ClassLibrary проекту. Але головний DisAdvantage цього засобу будування ASP.NET сайтів - що досі не знаю, як можна міняти код проекту без перезапуску, тобто щоб працювала фонова компіляція VB-код. Therefore все інше для мене має жодного значення. Але щоб ви побачили різницю, я зробив продовження у not liked for me типу проекта.
Взагалі у цьому типи проєкту навіть звичайна отладка неможлива без хитрощів, наприклад у моему environment'і мені навіть потрібно знімати галку OnlyMyCode.
Зверніть увагу, друзі, що існує багато різних типів проєктів, не тільки безпроєктний або простий проєкт MVC, найбільш поширений проєкт зараз зовсім інший - WebApi. Але не будемо на цьому зупинятися, якщо цікаво, подивиться будь ласку цю сторінку - How classic ASP.NET programmers has realized WEB.API since 2005 year (eng).
Ну взагалі у ASP.NET багато чого можна робити по різному, я вже багато разів писав що у ASP.NET існує щонайменше 4,164,044,800,000,000 варіантів утворення сайтів по самому поверховому рахунку Variants of ASP NET Technology stack, кожен програмер нахвалює лише свій засіб, а для молодих програмерів характерно, що вони взагалі нічого у світі не бачили й рахують що те що вони знають - це й є єдиний засіб утворення сайтів. Але, друзі - почитайте скільки у мене проектів, от наприклад у 2016-му році я тільки описи зробив 20-ти проєктів Опис двадцяти моїх дрібних фрілансерских проєктів 2016-го року. - і у жодному з них середовище розробки не повторювало інше. Тому не дивуйтесь, що навіть автори цього всесвітньо відомого прикладу не змогли зробити цього на VB, бо в них виникли непереборні проблеми. Ну це ми трохи пішли у сторону, щоб ви зрозуміли, наскільки багато варіантів існує, не тільки проєктно-безпроєктно.
3.2. Стартовий MVC-project Contoso University in VB.
Отже тут буде трохи магії, яку не змогли перебороти автори цього прикладу, я законвертував їх проєкт у VB та додав туди логери EntityFramework. Це буде наш стартовий проєкт, з якого почнеться ця сторінка. Проєкт цей ви можете завантажити собі звідси ASP.NET Contoso University Code First start project in VB with Logger and Migration.zip
На що тут потрібно звернути увагу у цьому проєкті?
- Це повноцінний MVC проєкт, тобто у ньому прілінковані не просто три бібліотеки, які ми взагалі додавали ручками у попередньому проєкті, а 27 бібліотек, більшість я яких не має сенсу, але дещо дуже важливо, тобто Razor та MVC.
- У цьому проєкті нормально працює NameSpace, тобто всі класи у всіх папочках нормально компілюються, у попередньому проєкті це не так. Тому ще цей проєкт має повноцінній PRJ-файл з повним описом всіх фолдеров для компіляції.
- У проєкті у першій частині у мене автоматично чіплявся клас EF_Config, як потомок класу DbConfiguration. У цьому проєкті так не працює, тому я зачепив його ручками (скрін нище).
- Доречі, зверніть увагу на перевагу проєктної архітектури (скрин вище) - файлік Global.ASAX тут не ублюдочний, з простого ASP, а нормальний з усіма можливими секціями і працюючим Intellisense.
- У цьому проєкті працює міграція (на відміну від попереднього, де вона у мене не запрацювала та я зробив свій власний виклик утворення бази). Тут все працює як по підручнику - Up and Down версій та метод SEED. Цікаво що у перших версіях цього проєкту у мене нормально чіплявся DbInitializer через Web.config (закоменчено нище на першому скріні), а потім це зламалося чомусь, хоча я не змінював RootNamespace.
3.3. Attributes and Fluent API.
Цей проєкт має два типа утворення даних у базі - через атрибути, якось так:
1: Imports System.ComponentModel.DataAnnotations
2: Imports System.ComponentModel.DataAnnotations.Schema
3:
4: Namespace Models
5:
6: Public Class Department
7:
8: Public Property DepartmentID As Integer
9:
10: <StringLength(50, MinimumLength:=3)>
11: Public Property Name As String
12:
13: <DataType(DataType.Currency)>
14: <Column(TypeName:="money")>
15: Public Property Budget As Decimal
16:
17: <DataType(DataType.Date)>
18: <DisplayFormat(DataFormatString:="{0:yyyy-MM-dd}", ApplyFormatInEditMode:=True)>
19: <Display(Name:="Start Date")>
20: Public Property StartDate As DateTime
21:
22: Public Property InstructorID As Integer?
23:
24: <Timestamp>
25: Public Property RowVersion As Byte()
26:
27: Public Property Administrator As Instructor
28:
29: Public Property Courses As ICollection(Of Course)
30: End Class
31: End Namespace
Та через Fluent API, тобто ось так:
1: Imports System
2: Imports System.Data.Entity.Migrations
3: Imports Microsoft.VisualBasic
4:
5: Namespace Migrations
6: Public Partial Class InitialCreate
7: Inherits DbMigration
8:
9: Public Overrides Sub Up()
10: CreateTable(
11: "dbo.CourseAssignment",
12: Function(c) New With
13: {
14: .CourseID = c.Int(nullable := False),
15: .InstructorID = c.Int(nullable := False)
16: }) _
17: .PrimaryKey(Function(t) New With { t.CourseID, t.InstructorID }) _
18: .ForeignKey("dbo.Course", Function(t) t.CourseID, cascadeDelete := True) _
19: .ForeignKey("dbo.Instructor", Function(t) t.InstructorID) _
20: .Index(Function(t) t.CourseID) _
21: .Index(Function(t) t.InstructorID)
22: ...
More about attributes Use attribute for custom validation function, Use jQuery Unobtrusive Validation, custom attributes for validation and validation service/controller, Use CustomAttribute to store metadata about model field, Use UIHint attribute to define template for EditorFor and DisplayFor helpers.
3.4. Перелік атрибутів Data Annotations.
Атрибути - це маркери методів або класів, їх вичитують якись проги як дані за допомогою рефлекшен. Я так тоже роблю майже у всіх своїх проєктах, ось наприклад тут - Аналіз MVC-сайту за допомогою System.Reflection Атрибутів. Це дозволяє уникнути специфічних назв класів, наприклад HomeController та використовувати які завгодно імена, з одного боку. А з іншого боку дозволяє скоротити код, тобто не писати кожного разу перевірку довжини поля, наприклад, а просто записати поруч з текстовим полем валідатор довжини, до того ж, ASP.NET побудований так, що ці довжина буде перевірятися не тільки на сервері, а й у браузері (що дуже корисно).
Можна зробити самостійно тестову валідацію у окремому консольному проєкті ось так. До речі неважко додати й свої власні атрибути та використовувати їх якось у своїх прогах. Але мікрософтовські індуси вже додали 20-30 найбільш поширених атрибутів, яки читаються как валідаторами, так і самою студією (наприклад Scafford плагіном), так і кодом EF.
Їх непогано було б поділити на декілька категорій, залежно від того, якою саме прогою вони читаються (EF, клієнтським валідатором, VS або іншими). Але це не так просто, бо деякі атрибути читаются різними прогами, а по друге я навіть не знайшов офіційний перелік ціх атрибутів. Перелік нище неточний, бо я його зробив за 10 секунд. Повний перелік знаходиться нище - 3.6 Close look to controller code.
- EF Modelling Attributes (Key, Timestamp, Table, Column, Index, ForeignKey, NotMapped, Association, DataType, DatabaseGenerated, ComplexType, InverseProperty)
- Client/Server Validation Attributes (Required, Range, MinLength, MaxLength, StringLengt, CreditCard, CustomValidation, EmailAddress, EnumDataType, FileExtensions, Phone, RegularExpression, Url)
- Display Attributes (DisplayColumn, Display, DisplayFormat, Editable)
- Other (ScaffoldColumn, ScaffoldTable, ConcurrencyCheck, BindableType, Compare, FilterUIHint, UIHint, MetadataType)
Саме ці DataAnnotation дозволяють утворити достатньо складний код за один клік мишкою.
3.5. Scaffold template and custom scaffold template.
Scaffold template - це найпростіший засіб отримати хоч якусь економію часу та автоматично отримати код контролеру та форм для найпростіших CRUD операцій. Тобто для CreateUpdateDelete для найпростіших табличок-довідників. Це задачка з абетки, наприклад мені кожного разу ії сують на тестах Декілька моїх останніх тестових проєктів., але найбільш цікаво те, що у реальних проєктах, мені здається, що не більше 10% процентів форм можливо побудувати таким чином. Я ось навмисно узяв і проаналізував пару своїх великих MVC проектів, от наприклад тут Электронный магазин запчастей SHEL-AUTO.RU на web-сервисах EMEX.RU можливо побудувати усього дві форми з біля 200, усі інші форми набагато складніші. Ось тут Social network for Canada with printed version of calendar to communities можна у адмінці всі прості форми побудувати за допомогою цього мастера, тобто не меньш 10% форм. Ось тут Проекты нового Вотпуска їх взагалі неможна використати, бо немає табличок з ключами у вигляді простих цілих, що вимагає для роботи EF, ось тут SPA-page на Classic ASP.NET та jQuery. потрібні ті ж самі CRUD-операції, але у вигляді SPA-сторінок. Тобто я хочу вас застережити від індуської реклами - так, існує такий метод автогенерації кода як Scaffold - але я не впевнений, що його можна застосувати хоч до 10% форм у реальних проєктах.
До речі, одна з найпоширених задач фрілансу, коли індуси "знімають пенку", тобто роблять щось подібне до проєкту саме за допомогою найпростіших Scaffold-автогенераторів, а потім соскакують з проєкту. А мене було безліч подібних проєктів, пару я навіть записав. Ось наприклад такий фрагмент My project for Nairobi, Kenya (ASP.NET Classic, VB.NET, NET 4.5, Bootstrap, Entity Framework) - індуси зробили найпростіші автогенеровані сторінки, а далі ії потрібно було ускладнювати та переробляти на Bootstrap. Тут немає автогенерації, це потрібно багато днів ручками стрічку за стрічкою переробляти ручками - з такої роботи індуси відразу морозяться і недороблений сайт попадає на фріланс. Тобто пенки з нього вже зняли, 80% процентів грошей власник проєкту вже заплатив за перший день роботи над проєктом, але проєкт після першого дня готовий фактично лише на 1% та уявляє з себе не більш ніж автоенеровані форми, які ще налаштовувати та налаштовувати (може не один місяць) - а грошей у проєкті вже немає. До речі, існує технология власних автогенераторів Creating a Custom Scaffolder for Visual Studio, такі речі як форми на Boostrap у проєкті, що на відео, мабуть простіше було б спочатку зробити власний автогенератор, ніж переробляти стандартний автогенерирований код. Крім того, існуючий автогенератор можна налаштовувати за допомогою макросів T4 How to customize the generated files from the New Scaffolded . Нажаль, поки що у мене не було проєктів, де налаштування автогенератора або власні автогенератори були в економічно обґрунтовані. Ну може тому, що (як я казав вище) у комерційних проєктах взагалі існує не так багато таких простих форм, які можна зробити автогенератором.
Інша цікава особливість цього метода автогенераціЇ кода, що він потребує повністю цілісної моделі даних, тобто він перевіряє всю модель, а не одну табличку, яку вам потрібно. Тобто ви повинні сама атрибутами побудувати повністю коректну модель, якщо це не так, то ви навіть для найменш важливого свого довідника не отримуєте автогенерацію кода. Тобто для цієї сторінки я взяв код с прикладу ContosoUneversity, і просто зробив конвертацію C# у VB, ніяк не змінюючи базу та відносини між табличками. Але навіть форму для студентів я не зміг отримати автоматично, поки не змінив схему у зовсім іншому місці, ніяк з студентами не пов'язаною.
Але якщо ви розібралися з застосуванням усіх атрибутів, правильно побудували усі відносини 1:1, 1:M, M:M між табличками, то далі все буде просто - цей мастер вам утворить код автоматично.
3.6. Close look to controller code.
Якщо, друзі, ви подивитесь на код контролеру, то по перше він теж насичений атрибутами. Що взагалі означає бути MVC-програмістом? Це означати пам'ятати більшість цих класів, їх методів, розуміти їх призначення, та коректно їх використовувати.
По-перше, є атрибути Entity Framework, їх дуже багато, вони визначені у самому NET Framework (у System.ComponentModel.DataAnnotations та System.ComponentModel.DataAnnotations.Schema Attributes), а Entity Framework їх обробляє. Ось їх перелік - AssociationAttribute ,BindableTypeAttribute ,CompareAttribute ,ConcurrencyCheckAttribute ,CreditCardAttribute ,CustomValidationAttribute ,DataTypeAttribute ,DisplayAttribute ,DisplayColumnAttribute ,DisplayFormatAttribute ,EditableAttribute ,EmailAddressAttribute ,EnumDataTypeAttribute ,FileExtensionsAttribute ,FilterUIHintAttribute ,KeyAttribute ,MaxLengthAttribute ,MetadataTypeAttribute ,MinLengthAttribute ,PhoneAttribute ,RangeAttribute ,RegularExpressionAttribute ,RequiredAttribute ,ScaffoldColumnAttribute ,ScaffoldTableAttribute ,StringLengthAttribute ,TimestampAttribute ,UIHintAttribute ,UrlAttribute ,ValidationAttribute ,ColumnAttribute, ComplexTypeAttribute, DatabaseGeneratedAttribute, ForeignKeyAttribute, InversePropertyAttribute, NotMappedAttribute, TableAttribute.
По-друге існують атрибути MVC, яких тоже чимало, ось їх перелік з MVC 5 - AcceptVerbsAttribute ,ActionFilterAttribute ,ActionMethodSelectorAttribute ,ActionNameAttribute ,ActionNameSelectorAttribute ,AdditionalMetadataAttribute ,AllowAnonymousAttribute ,AllowHtmlAttribute ,AsyncTimeoutAttribute ,AuthorizeAttribute ,BindAttribute ,CachedDataAnnotationsMetadataAttributes ,ChildActionOnlyAttribute ,CompareAttribute ,CustomModelBinderAttribute ,DataAnnotationsModelValidator
,FilterAttribute ,FilterAttributeFilterProvider ,HandleErrorAttribute ,HiddenInputAttribute ,HttpDeleteAttribute ,HttpGetAttribute ,HttpHeadAttribute ,HttpOptionsAttribute ,HttpPatchAttribute ,HttpPostAttribute ,HttpPutAttribute ,MaxLengthAttributeAdapter ,MinLengthAttributeAdapter ,ModelBinderAttribute ,NoAsyncTimeoutAttribute ,NonActionAttribute ,OutputCacheAttribute ,OverrideActionFiltersAttribute ,OverrideAuthenticationAttribute ,OverrideAuthorizationAttribute ,OverrideExceptionFiltersAttribute ,OverrideResultFiltersAttribute ,RangeAttributeAdapter ,RegularExpressionAttributeAdapter ,RemoteAttribute ,RequiredAttributeAdapter ,RequireHttpsAttribute ,RouteAreaAttribute ,RouteAttribute ,RouteCollectionAttributeRoutingExtensions ,RoutePrefixAttribute ,SessionStateAttribute ,StringLengthAttributeAdapter ,ValidateAntiForgeryTokenAttribute ,ValidateInputAttribute. По-трете, код MVC-контролеру використовує специфічні обьекти ASP.NET MVC, які я перерахував ось тут ще у 2010-му році для MVC 3 Мой первый сайт на MVC 3 Razor. (ось тут є новий перелік обьектів MVC 5.2). Взагалі цих обьектів приблизно 250 штук, ось вони, без Атрибутів, які були перераховані вище - ActionDescriptor ,ActionExecutedContext ,ActionExecutingContext ,ActionResult ,AjaxHelper ,AjaxHelper
,AjaxRequestExtensions ,AreaRegistration ,AreaRegistrationContext ,AssociatedMetadataProvider ,AssociatedValidatorProvider ,AsyncController ,AuthorizationContext ,BuildManagerCompiledView ,BuildManagerViewEngine ,ByteArrayModelBinder ,CachedAssociatedMetadataProvider ,CachedDataAnnotationsModelMetadata ,CachedDataAnnotationsModelMetadataProvider ,CachedModelMetadata ,CancellationTokenModelBinder ,ChildActionValueProvider ,ChildActionValueProviderFactory ,ClientDataTypeModelValidatorProvider ,ContentResult ,Controller ,ControllerActionInvoker ,ControllerBase ,ControllerBuilder ,ControllerContext ,ControllerDescriptor ,ControllerInstanceFilterProvider ,DataAnnotationsModelMetadata ,DataAnnotationsModelMetadataProvider ,DataAnnotationsModelValidator ,DataAnnotationsModelValidatorProvider ,DataErrorInfoModelValidatorProvider ,DefaultControllerFactory ,DefaultModelBinder ,DefaultViewLocationCache ,DependencyResolver ,DependencyResolverExtensions ,DictionaryValueProvider ,EmptyModelMetadataProvider ,EmptyModelValidatorProvider ,EmptyResult ,ExceptionContext ,ExpressionHelper ,FieldValidationMetadata ,FileContentResult ,FilePathResult ,FileResult ,FileStreamResult ,Filter ,FilterInfo ,FilterProviderCollection ,FilterProviders ,FormCollection ,FormContext ,FormValueProvider ,FormValueProviderFactory ,GlobalFilterCollection ,GlobalFilters ,HandleErrorInfo ,HtmlHelper ,HtmlHelper ,HttpFileCollectionValueProvider ,HttpFileCollectionValueProviderFactory ,HttpNotFoundResult ,HttpPostedFileBaseModelBinder ,HttpRequestExtensions ,HttpStatusCodeResult ,HttpUnauthorizedResult ,JavaScriptResult ,JQueryFormValueProvider ,JQueryFormValueProviderFactory ,JsonResult ,JsonValueProviderFactory ,LinqBinaryModelBinder ,ModelBinderDictionary ,ModelBinderProviderCollection ,ModelBinderProviders ,ModelBinders ,ModelBindingContext ,ModelError ,ModelErrorCollection ,ModelMetadata ,ModelMetadataProvider ,ModelMetadataProviders ,ModelState ,ModelStateDictionary ,ModelValidationResult ,ModelValidator ,ModelValidatorProvider ,ModelValidatorProviderCollection ,ModelValidatorProviders ,MultiSelectList ,MvcFilter ,MvcHandler ,MvcHtmlString ,MvcHttpHandler ,MvcRouteHandler ,MvcWebRazorHostFactory ,NameValueCollectionExtensions ,NameValueCollectionValueProvider ,ParameterBindingInfo ,ParameterDescriptor ,PartialViewResult ,PreApplicationStartCode ,QueryStringValueProvider ,QueryStringValueProviderFactory ,RazorView ,RazorViewEngine ,RedirectResult ,RedirectToRouteResult ,ReflectedActionDescriptor ,ReflectedControllerDescriptor ,ReflectedParameterDescriptor ,ResultExecutedContext ,ResultExecutingContext ,RouteCollectionExtensions ,RouteDataValueProvider ,RouteDataValueProviderFactory ,SelectList ,SelectListGroup ,SelectListItem ,SessionStateTempDataProvider ,TempDataDictionary ,TemplateInfo ,UrlHelper ,UrlParameter ,ValidatableObjectAdapter ,ValueProviderCollection ,ValueProviderDictionary ,ValueProviderFactories ,ValueProviderFactory ,ValueProviderFactoryCollection ,ValueProviderResult ,ViewContext ,ViewDataDictionary ,ViewDataDictionary ,ViewDataInfo ,ViewEngineCollection ,ViewEngineResult ,ViewEngines ,ViewMasterPage ,ViewMasterPage ,ViewPage ,ViewPage ,ViewResult ,ViewResultBase ,ViewStartPage ,ViewTemplateUserControl ,ViewTemplateUserControl ,ViewType ,ViewUserControl ,ViewUserControl ,VirtualPathProviderViewEngine ,WebFormView ,WebFormViewEngine ,WebViewPage ,WebViewPage ,Interfaces ,IActionFilter ,IActionInvoker ,IActionInvokerFactory ,IAuthorizationFilter ,IClientValidatable ,IController ,IControllerActivator ,IControllerFactory ,IDependencyResolver ,IEnumerableValueProvider ,IExceptionFilter ,IFilterProvider ,IMetadataAware ,IMethodInfoActionDescriptor ,IModelBinder ,IModelBinderProvider ,IMvcFilter ,IResultFilter ,IRouteWithArea ,ITempDataProvider ,ITempDataProviderFactory ,IUnvalidatedValueProvider ,IValueProvider ,IView ,IViewDataContainer ,IViewEngine ,IViewLocationCache ,IViewPageActivator ,Enums ,AreaReference ,FilterScope ,FormMethod ,Html5DateRenderingMode ,HttpVerbs ,InputType ,JsonRequestBehavior ,Delegates ,ActionSelector ,DataAnnotationsModelValidationFactory ,DataAnnotationsValidatableObjectAdapterFactory. Зверніть увагу, що деякі об'єкти, наприклад HtmlHelper, мають до 240 методів. HtmlHelper(ViewContext, IViewDataContainer) ,HtmlHelper(ViewContext, IViewDataContainer, RouteCollection) ,ValidationInputCssClassName ,ValidationInputValidCssClassName ,ValidationMessageCssClassName ,ValidationMessageValidCssClassName ,ValidationSummaryCssClassName ,ValidationSummaryValidCssClassName ,Properties ,ClientValidationEnabled ,Html5DateRenderingMode ,IdAttributeDotReplacement ,RouteCollection ,UnobtrusiveJavaScriptEnabled ,ValidationMessageElement ,ValidationSummaryMessageElement ,ViewBag ,ViewContext ,ViewData ,ViewDataContainer ,AnonymousObjectToHtmlAttributes(Object) ,AntiForgeryToken() ,AntiForgeryToken(String) ,AntiForgeryToken(String, String, String) ,AttributeEncode(Object) ,AttributeEncode(String) ,EnableClientValidation() ,EnableClientValidation(Boolean) ,EnableUnobtrusiveJavaScript(Boolean) ,EnableUnobtrusiveJavaScript() ,Encode(Object) ,Encode(String) ,FormatValue(Object, String) ,GenerateIdFromName(String) ,GenerateIdFromName(String, String) ,GenerateLink(RequestContext, RouteCollection, String, String, String, String, RouteValueDictionary, IDictionary
) ,GenerateLink(RequestContext, RouteCollection, String, String, String, String, String, String, String, RouteValueDictionary, IDictionary ) ,GenerateRouteLink(RequestContext, RouteCollection, String, String, RouteValueDictionary, IDictionary ) ,GenerateRouteLink(RequestContext, RouteCollection, String, String, String, String, String, RouteValueDictionary, IDictionary ) ,GetFormMethodString(FormMethod) ,GetInputTypeString(InputType) ,GetUnobtrusiveValidationAttributes(String, ModelMetadata) ,GetUnobtrusiveValidationAttributes(String) ,HttpMethodOverride(String) ,HttpMethodOverride(HttpVerbs) ,ObjectToDictionary(Object) ,Raw(Object) ,Raw(String) ,SetValidationMessageElement(String) ,SetValidationSummaryMessageElement(String) ,Extension Methods ,Action(HtmlHelper, String) ,Action(HtmlHelper, String, Object) ,Action(HtmlHelper, String, String) ,Action(HtmlHelper, String, String, Object) ,Action(HtmlHelper, String, String, RouteValueDictionary) ,Action(HtmlHelper, String, RouteValueDictionary) ,RenderAction(HtmlHelper, String) ,RenderAction(HtmlHelper, String, Object) ,RenderAction(HtmlHelper, String, String) ,RenderAction(HtmlHelper, String, String, Object) ,RenderAction(HtmlHelper, String, String, RouteValueDictionary) ,RenderAction(HtmlHelper, String, RouteValueDictionary) ,Display(HtmlHelper, String) ,Display(HtmlHelper, String, Object) ,Display(HtmlHelper, String, String) ,Display(HtmlHelper, String, String, Object) ,Display(HtmlHelper, String, String, String) ,Display(HtmlHelper, String, String, String, Object) ,DisplayForModel(HtmlHelper) ,DisplayForModel(HtmlHelper, Object) ,DisplayForModel(HtmlHelper, String) ,DisplayForModel(HtmlHelper, String, Object) ,DisplayForModel(HtmlHelper, String, String) ,DisplayForModel(HtmlHelper, String, String, Object) ,DisplayName(HtmlHelper, String) ,DisplayNameForModel(HtmlHelper) ,DisplayText(HtmlHelper, String) ,Editor(HtmlHelper, String) ,Editor(HtmlHelper, String, Object) ,Editor(HtmlHelper, String, String) ,Editor(HtmlHelper, String, String, Object) ,Editor(HtmlHelper, String, String, String) ,Editor(HtmlHelper, String, String, String, Object) ,EditorForModel(HtmlHelper) ,EditorForModel(HtmlHelper, Object) ,EditorForModel(HtmlHelper, String) ,EditorForModel(HtmlHelper, String, Object) ,EditorForModel(HtmlHelper, String, String) ,EditorForModel(HtmlHelper, String, String, Object) ,BeginForm(HtmlHelper) ,BeginForm(HtmlHelper, Object) ,BeginForm(HtmlHelper, String, String) ,BeginForm(HtmlHelper, String, String, Object) ,BeginForm(HtmlHelper, String, String, Object, FormMethod) ,BeginForm(HtmlHelper, String, String, Object, FormMethod, Object) ,BeginForm(HtmlHelper, String, String, FormMethod) ,BeginForm(HtmlHelper, String, String, FormMethod, IDictionary ) ,BeginForm(HtmlHelper, String, String, FormMethod, Object) ,BeginForm(HtmlHelper, String, String, RouteValueDictionary) ,BeginForm(HtmlHelper, String, String, RouteValueDictionary, FormMethod) ,BeginForm(HtmlHelper, String, String, RouteValueDictionary, FormMethod, IDictionary ) ,BeginForm(HtmlHelper, RouteValueDictionary) ,BeginRouteForm(HtmlHelper, Object) ,BeginRouteForm(HtmlHelper, String) ,BeginRouteForm(HtmlHelper, String, Object) ,BeginRouteForm(HtmlHelper, String, Object, FormMethod) ,BeginRouteForm(HtmlHelper, String, Object, FormMethod, Object) ,BeginRouteForm(HtmlHelper, String, FormMethod) ,BeginRouteForm(HtmlHelper, String, FormMethod, IDictionary ) ,BeginRouteForm(HtmlHelper, String, FormMethod, Object) ,BeginRouteForm(HtmlHelper, String, RouteValueDictionary) ,BeginRouteForm(HtmlHelper, String, RouteValueDictionary, FormMethod) ,BeginRouteForm(HtmlHelper, String, RouteValueDictionary, FormMethod, IDictionary ) ,BeginRouteForm(HtmlHelper, RouteValueDictionary) ,EndForm(HtmlHelper) ,CheckBox(HtmlHelper, String) ,CheckBox(HtmlHelper, String, Boolean) ,CheckBox(HtmlHelper, String, Boolean, IDictionary ) ,CheckBox(HtmlHelper, String, Boolean, Object) ,CheckBox(HtmlHelper, String, IDictionary ) ,CheckBox(HtmlHelper, String, Object) ,Hidden(HtmlHelper, String) ,Hidden(HtmlHelper, String, Object) ,Hidden(HtmlHelper, String, Object, IDictionary ) ,Hidden(HtmlHelper, String, Object, Object) ,Password(HtmlHelper, String) ,Password(HtmlHelper, String, Object) ,Password(HtmlHelper, String, Object, IDictionary ) ,Password(HtmlHelper, String, Object, Object) ,RadioButton(HtmlHelper, String, Object) ,RadioButton(HtmlHelper, String, Object, Boolean) ,RadioButton(HtmlHelper, String, Object, Boolean, IDictionary ) ,RadioButton(HtmlHelper, String, Object, Boolean, Object) ,RadioButton(HtmlHelper, String, Object, IDictionary ) ,RadioButton(HtmlHelper, String, Object, Object) ,TextBox(HtmlHelper, String) ,TextBox(HtmlHelper, String, Object) ,TextBox(HtmlHelper, String, Object, IDictionary ) ,TextBox(HtmlHelper, String, Object, Object) ,TextBox(HtmlHelper, String, Object, String) ,TextBox(HtmlHelper, String, Object, String, IDictionary ) ,TextBox(HtmlHelper, String, Object, String, Object) ,Label(HtmlHelper, String) ,Label(HtmlHelper, String, IDictionary ) ,Label(HtmlHelper, String, Object) ,Label(HtmlHelper, String, String) ,Label(HtmlHelper, String, String, IDictionary ) ,Label(HtmlHelper, String, String, Object) ,LabelForModel(HtmlHelper) ,LabelForModel(HtmlHelper, IDictionary ) ,LabelForModel(HtmlHelper, Object) ,LabelForModel(HtmlHelper, String) ,LabelForModel(HtmlHelper, String, IDictionary ) ,LabelForModel(HtmlHelper, String, Object) ,ActionLink(HtmlHelper, String, String) ,ActionLink(HtmlHelper, String, String, Object) ,ActionLink(HtmlHelper, String, String, Object, Object) ,ActionLink(HtmlHelper, String, String, String) ,ActionLink(HtmlHelper, String, String, String, Object, Object) ,ActionLink(HtmlHelper, String, String, String, String, String, String, Object, Object) ,ActionLink(HtmlHelper, String, String, String, String, String, String, RouteValueDictionary, IDictionary ) ,ActionLink(HtmlHelper, String, String, String, RouteValueDictionary, IDictionary ) ,ActionLink(HtmlHelper, String, String, RouteValueDictionary) ,ActionLink(HtmlHelper, String, String, RouteValueDictionary, IDictionary ) ,RouteLink(HtmlHelper, String, Object) ,RouteLink(HtmlHelper, String, Object, Object) ,RouteLink(HtmlHelper, String, String) ,RouteLink(HtmlHelper, String, String, Object) ,RouteLink(HtmlHelper, String, String, Object, Object) ,RouteLink(HtmlHelper, String, String, String, String, String, Object, Object) ,RouteLink(HtmlHelper, String, String, String, String, String, RouteValueDictionary, IDictionary ) ,RouteLink(HtmlHelper, String, String, RouteValueDictionary) ,RouteLink(HtmlHelper, String, String, RouteValueDictionary, IDictionary ) ,RouteLink(HtmlHelper, String, RouteValueDictionary) ,RouteLink(HtmlHelper, String, RouteValueDictionary, IDictionary ) ,Id(HtmlHelper, String) ,IdForModel(HtmlHelper) ,Name(HtmlHelper, String) ,NameForModel(HtmlHelper) ,Partial(HtmlHelper, String) ,Partial(HtmlHelper, String, Object) ,Partial(HtmlHelper, String, Object, ViewDataDictionary) ,Partial(HtmlHelper, String, ViewDataDictionary) ,RenderPartial(HtmlHelper, String) ,RenderPartial(HtmlHelper, String, Object) ,RenderPartial(HtmlHelper, String, Object, ViewDataDictionary) ,RenderPartial(HtmlHelper, String, ViewDataDictionary) ,DropDownList(HtmlHelper, String) ,DropDownList(HtmlHelper, String, IEnumerable ) ,DropDownList(HtmlHelper, String, IEnumerable , IDictionary ) ,DropDownList(HtmlHelper, String, IEnumerable , Object) ,DropDownList(HtmlHelper, String, IEnumerable , String) ,DropDownList(HtmlHelper, String, IEnumerable , String, IDictionary ) ,DropDownList(HtmlHelper, String, IEnumerable , String, Object) ,DropDownList(HtmlHelper, String, String) ,ListBox(HtmlHelper, String) ,ListBox(HtmlHelper, String, IEnumerable ) ,ListBox(HtmlHelper, String, IEnumerable , IDictionary ) ,ListBox(HtmlHelper, String, IEnumerable , Object) ,TextArea(HtmlHelper, String) ,TextArea(HtmlHelper, String, IDictionary ) ,TextArea(HtmlHelper, String, Object) ,TextArea(HtmlHelper, String, String) ,TextArea(HtmlHelper, String, String, IDictionary ) ,TextArea(HtmlHelper, String, String, Int32, Int32, IDictionary ) ,TextArea(HtmlHelper, String, String, Int32, Int32, Object) ,TextArea(HtmlHelper, String, String, Object) ,Validate(HtmlHelper, String) ,ValidationMessage(HtmlHelper, String) ,ValidationMessage(HtmlHelper, String, IDictionary ) ,ValidationMessage(HtmlHelper, String, IDictionary , String) ,ValidationMessage(HtmlHelper, String, Object) ,ValidationMessage(HtmlHelper, String, Object, String) ,ValidationMessage(HtmlHelper, String, String) ,ValidationMessage(HtmlHelper, String, String, IDictionary ) ,ValidationMessage(HtmlHelper, String, String, IDictionary , String) ,ValidationMessage(HtmlHelper, String, String, Object) ,ValidationMessage(HtmlHelper, String, String, Object, String) ,ValidationMessage(HtmlHelper, String, String, String) ,ValidationSummary(HtmlHelper) ,ValidationSummary(HtmlHelper, Boolean) ,ValidationSummary(HtmlHelper, Boolean, String) ,ValidationSummary(HtmlHelper, Boolean, String, IDictionary ) ,ValidationSummary(HtmlHelper, Boolean, String, IDictionary , String) ,ValidationSummary(HtmlHelper, Boolean, String, Object) ,ValidationSummary(HtmlHelper, Boolean, String, Object, String) ,ValidationSummary(HtmlHelper, Boolean, String, String) ,ValidationSummary(HtmlHelper, String) ,ValidationSummary(HtmlHelper, String, IDictionary ) ,ValidationSummary(HtmlHelper, String, IDictionary , String) ,ValidationSummary(HtmlHelper, String, Object) ,ValidationSummary(HtmlHelper, String, Object, String) ,ValidationSummary(HtmlHelper, String, String) ,Value(HtmlHelper, String) ,Value(HtmlHelper, String, String) ,ValueForModel(HtmlHelper) ,ValueForModel(HtmlHelper, String). Четвертий пазл цього малюнка - класи NET Framework, які угруповані у 54 простірах імен, які постійно поширюються - Accessibility,Microsoft.Activities,Microsoft.Build,Microsoft.CSharp,Microsoft.JScript,Microsoft.SqlServer.Server,Microsoft.VisualBasic,Microsoft.VisualC,Microsoft.Win32,Microsoft.Windows,System,System.Activities,System.AddIn,System.CodeDom,System.Collections,System.ComponentModel,System.Configuration,System.Data,System.Deployment,System.Device.Location,System.Diagnostics,System.DirectoryServices,System.Drawing,System.Dynamic,System.EnterpriseServices,System.Globalization,System.IdentityModel,System.IO,System.Linq,System.Management,System.Media,System.Messaging,System.Net,System.Numerics,System.Printing,System.Reflection,System.Resources,System.Runtime,System.Security,System.ServiceModel,System.ServiceProcess,System.Speech,System.Text,System.Threading,System.Timers,System.Transactions,System.Web,System.Windows,System.Workflow,System.Xaml,System.Xml,UIAutomationClientsideProviders,XamlGeneratedNamespace. Загальна кількість класів у NET 4.7 більше 100 тисяч.
І п'ятий пазл цього малюнка - це Razor VB syntax, який відрізняється від C# сінтаксісу, подивитися на коректний VB-syntax ви можете на моєї сторінці 2012-го року (шукайте розділ RAZOR SYNTAX) Difference between VB and C#.
3.7. Виготовлення власних Extension-хелперов.
Ця ремарка, як и наступна, стосується взагалі програмування MVC. Існують так звані Extension-функції, це такий цікавий викидень обьектного програмування, коли ви можете додавати у класі-потомці свою власну функції до статичного блока функцій базового класу і якщо ви зробили імпорт вашої extension-функції, то можете неї користуватися у будь якому місці. Extension-функції також мають цікавий сінтаксіс, тобто перший параметр у них - це клас який ви поширюєте. У мене на сайті опублікована безліч різноманітних функцій - ви можете побачити як вини пишуться - наприклад Змінні Nullable та як обробляти DBNull з бази за допомогою Extension-функції, Мої поширення Linq-to-SQL, How to reorder DataRow with Extension function, Anonymous types, Lambda Expression and Linq Special Row Comparer (eng), Expanding opportunities of Classic ASP.NET with generic extension function FindBaseClassRecursively (eng), Amazing extension function CopyLinqDataMembersByName to expand Linq-to-SQL (eng). Мені ці можливість подобається і їх пишу достатньо часто.
У MVC існує немало стандартних Extension хелперов.
Але найбільш корисно, як мабуть ви вже зрозуміли, є написання власних хелперов. Це мабуть трохи теж саме ніж власні scafford-template, але на молекулярному рівні. How to create Razor html-helper in VB.NET, Define common code as Function and Helpers (directly in View and in the codeBehind).
3.8. Store data in ViewState/ViewBag/ViewData/TempData
Ще одна найважливіша річ, без якої неможливо зробити навіть найпростіший сайт - це яким чином зберігати дані, які передаються на форму - та як передати дані на сервері між різними класами (наприклад класом, що рендеріть форму та класом контролеру). Сама назва MVC (Model-View-Controller) має на увазі дані, які у формі Model виготовляються контролером та передаються у View для демонстрації у відформатованому вигляді.
Тут є важливий додаток, як Web-сервер зв'язує кожного користувача сайта з його власними даними. Звичайно це робиться за допомогою куків ASPNETSESSIONID, які ви можете бачити у будь якому сайті ASP.NET. Але так буває не завжди, конкретні дані з юзером можуть зв'язуватися також за допомогою Session-сервера. Такий засіб у мене використовуються наприклад на порталі http://votpusk.ru, тобто залогінівшись у один сайт порталу ви опиняєтесь залогіненим у всіх сайтах порталу. Але й це лише інший, другий засів пов'язування користувачів сайту з його даними. Найбільш просунутий, який звичайно використовується у кластерах, коли десятки web-серверів обслуговують юзерів синхронно - це засіб пов'язування за допомогою SQL-сервера. У цьому році у мені як раз був такий проєкт, коли я якимось індусам пов'язав у кластер десяток серверів, ось тут налаштування такого зв'язку Transfer session between ASP.NET apps by SQL-server.
Але зв'язок користувача сайта з його власними сессіоними даними - це одне питання, а інше питання, у якоми вигляді зберігати дані та передавати їх на сервері між класами. Тут існує сім головних засобів.
- ViewState - використовується у класичному ASP.NET. Їх можна зберігати трьома засобами - у обьекті CACHE, у SQL-сервері та безпосередньо на сторінці. Почните вивчати цю тему з цих моїх сторінок, де ViewState активно використовується - Хранение состояния страниц на сервере, Изготовление отчетов в ASP.NET2, Мой первый фото-слайдер на Flex 4, Сайт для мобільників, Парсинг AJAX-сайтов в среде AIR (путем выполнения jQuery-запросов из ActionScript), OpenSource-проекты для работы с видео и торентами., SPA-page на Classic ASP.NET та jQuery.
- ViewData/ViewBag На MasterPage, тобто _Layout.vbhtml у термінах MVC, утворених Scaffold'ом, ви зможете побачити ось такий код:
ViewData взагалі можна використовувати замість однієї складної моделі, наприклад ось цей сайт я саме так и зробив - Электронный магазин запчастей SHEL-AUTO.RU на web-сервисах EMEX.RU, тобто у контролері ви завантажуєте дані ViewData("Additional")=X, а на формі ними користуєтесь X=ViewData("Additional").
ViewBag це теж самий ViewData, більш за все він нагадує класичний Object з VB6, користуватися ним точно так, тобто через посилання на Property.
- TempData - це звичайний Session, який звичайно використовується для передачи даних у межах сесії між контролерами.
- Ще один засіб зберігання даних - це об'єкт CACHE, я ним не дуже користуюсь, бо вистачає інших можливостей, але інші програмісти користуються активно. Я, навпаки, активно користуюся об'єктами HttpContext.Current.Application та Session, часто завантажую у них дані (наприклад якісь невеличкі довідники з бази) під час старта сесії або сайта, щоб потім не звертатися у базу, а потім, коли виникає необхідність у цих довідниках, дістаю їх з Application без звернення у базу - та користуюсь ними.
- Передача даних можлива також через між формами, або між різними станами форми можлива також через HiddenField - принципово це нагадує засіб передач даних через параметри URL, але HiddenField передається не по GET, а по POST та їх довжина може бути набагато більше.
- Для тих самих цілій зберігання даних можливо таке використовувати COOKIE браузера, до речі більшість перерахованих вище заслбів - це надбудова над COOKIE, де httponly cookie використовуєтья як KEY для утворення Session-об'єкту. TempData, наприклад, це чистий Session, а ViewData/ViewBag - це надбудова над Session.
- І останній засіб зберігання даних та передачі їх з форми на форму - через SQL-сервер, так звичайно передаються дані між юзерами, або зберігаються назавжди.
More - Save ModelState with Redirection.
More - https://www.c-sharpcorner.com/blogs/viewdata-vs-viewbag-vs-tempdata-in-mvc1
Entity Framework missing FAQ Part 3:
- 3.7 Склад стартового проєкту.
- 3.8 Deploy Database to SQL server.
- 3.8.1 Manually Deploy.
- 3.8.2 Визначення зв'язків даних 1:1, 1:M, M:M у базі та EF CodeFirst.
- 3.8.3 Visual Designer.
- 3.8.4 Unexpected Deploy.
- 3.9 Ще раз про Scaffold template.
- 3.9.1 Collection.Generic.List (of T), IQueryable vs IEnumerable
- 3.9.2 атрибут Bind
- 3.9.3 Антиспам валідатор Validate Anti Forgery Code
- 3.9.4 jquery.validate.unobtrusive.js
|