Mam następującą klasę wygenerowaną przez strukturę jednostki:
public partial class ItemRequest
{
public int RequestId { get; set; }
//...
Chciałbym, aby to pole było wymagane
[Required]
public int RequestId { get;set; }
Jednak ponieważ jest to wygenerowany kod, zostanie on usunięty. Nie wyobrażam sobie sposobu na utworzenie klasy częściowej, ponieważ właściwość jest zdefiniowana przez wygenerowaną klasę częściową. Jak w bezpieczny sposób zdefiniować ograniczenie?
c#
entity-framework
asp.net-mvc-4
P. Brian Mackey
źródło
źródło
Odpowiedzi:
Wygenerowana klasa
ItemRequest
zawsze będziepartial
klasą. Pozwala to na napisanie drugiej klasy częściowej, która jest oznaczona niezbędnymi adnotacjami danych. W twoim przypadku klasa częściowaItemRequest
wyglądałaby tak:using System.ComponentModel; using System.ComponentModel.DataAnnotations; //make sure the namespace is equal to the other partial class ItemRequest namespace MvcApplication1.Models { [MetadataType(typeof(ItemRequestMetaData))] public partial class ItemRequest { } public class ItemRequestMetaData { [Required] public int RequestId {get;set;} //... } }
źródło
Jak odpowiedział MUG4N , możesz używać klas częściowych, ale zamiast tego lepiej będzie używać interfejsów . W takim przypadku wystąpią błędy kompilacji, jeśli model EF nie odpowiada modelowi walidacji. Możesz więc modyfikować modele EF bez obawy, że reguły walidacji są nieaktualne.
using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace YourApplication.Models { public interface IEntityMetadata { [Required] Int32 Id { get; set; } } [MetadataType(typeof(IEntityMetadata))] public partial class Entity : IEntityMetadata { /* Id property has already existed in the mapped class */ } }
PS Jeśli używasz typu projektu, który różni się od ASP.NET MVC (podczas ręcznej weryfikacji danych) nie zapomnij zarejestrować swoich walidatorów
/* Global.asax or similar */ TypeDescriptor.AddProviderTransparent( new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));
źródło
Znalazłem rozwiązanie takie jak odpowiedź MUG4N , ale zamiast tego zagnieżdżając
MetaData
klasę w klasie encji, zmniejszając w ten sposób liczbę klas na publicznej liście przestrzeni nazw i eliminując potrzebę posiadania unikalnej nazwy dla każdej klasy metadanych.using System.ComponentModel.DataAnnotations; namespace MvcApplication1.Models { [MetadataType(typeof(MetaData))] public partial class ItemRequest { public class MetaData { [Required] public int RequestId; //... } } }
źródło
[NotMapped]
wewnątrz klasy częściowej, gdy ich potrzebuję.Jest to swego rodzaju rozszerzenie odpowiedzi @dimonser, jeśli zregenerujesz model bazy danych, będziesz musiał ręcznie ponownie dodać interfejsy do tych klas.
Jeśli masz do tego żołądek, możesz również zmodyfikować swoje
.tt
szablony:Oto przykład automatycznego generowania interfejsów w niektórych klasach, jest to fragment z metody
.tt
zastąpieniaEntityClassOpening
metody w twojej następującą (i oczywiścievar stringsToMatch
z nazwami jednostek i interfejsami).public string EntityClassOpening(EntityType entity) { var stringsToMatch = new Dictionary<string,string> { { "Answer", "IJourneyAnswer" }, { "Fee", "ILegalFee" } }; return string.Format( CultureInfo.InvariantCulture, "{0} {1}partial class {2}{3}{4}", Accessibility.ForType(entity), _code.SpaceAfter(_code.AbstractOption(entity)), _code.Escape(entity), _code.StringBefore(" : ", _typeMapper.GetTypeName(entity.BaseType)), stringsToMatch.Any(o => _code.Escape(entity).Contains(o.Key)) ? " : " + stringsToMatch.Single(o => _code.Escape(entity).Contains(o.Key)).Value : string.Empty); }
Jednak żaden normalny człowiek nie powinien sobie tego robić, zostało udowodnione w Biblii, że idzie się za to do piekła.
źródło
Nie jestem pewien, jak zrobić to, o co prosisz, ale można to obejść. Dynamiczne sprawdzanie poprawności danych przez zastąpienie GetValidators Twojego niestandardowego DataAnnotationsModelValidatorProvider. Możesz w nim przeczytać zasady walidacji każdego pola (z bazy danych, pliku konfiguracyjnego itp.) I dodać walidatory w razie potrzeby. Ma dodatkowe wartości, że walidacja nie jest już ściśle powiązana z modelem i można ją zmienić bez konieczności ponownego uruchamiania witryny. Oczywiście może to być przesada w twoim przypadku, ale w naszym przypadku było idealne!
źródło
Zmodyfikuj szablon T4, dodając wymagane adnotacje, plik ten zwykle nosi nazwę NAZWA MODELU.tt
dowiedzieć się, gdzie T4 tworzy klasę i metody, aby wiedzieć, gdzie je umieścić.
<#=codeStringGenerator.IgnoreJson(navigationProperty)#> //create this method in file public string IgnoreJson(NavigationProperty navigationProperty){ string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore] [IgnoreDataMember]"; return result; }
Będziesz także musiał dodać przestrzenie nazw;
<#=codeStringGenerator.UsingDirectives(inHeader: false)#> using System.ComponentModel.DataAnnotations; using Newtonsoft.Json; using System.Runtime.Serialization;
Przebuduj swoje klasy, zapisując model, wszystkie metody powinny być opatrzone adnotacjami.
źródło