Fügen Sie einer vom Entitätsframework generierten Klasse Datenanmerkungen hinzu


93

Ich habe die folgende Klasse vom Entity Framework generiert:

public partial class ItemRequest
{
    public int RequestId { get; set; }
    //...

Ich möchte dies zu einem Pflichtfeld machen

[Required]
public int RequestId { get;set; }

Da dies jedoch generierter Code ist, wird dieser gelöscht. Ich kann mir keine Möglichkeit vorstellen, eine Teilklasse zu erstellen, da die Eigenschaft durch die generierte Teilklasse definiert wird. Wie kann ich die Einschränkung sicher definieren?


Wenn Ihre Eigenschaft int ist, ist sie standardmäßig für modelbinder erforderlich, sodass Ihr Attribut [Erforderlich] hier nichts hinzufügt.
Kirill Bestemyanov

@KirillBestemyanov - @ Html.ValidationMessageFor (model => model.Item.Item.ResourceTypeID) sollte clientseitig fehlschlagen. Es tut nicht.
P.Brian.Mackey

Antworten:


143

Die generierte Klasse ItemRequestwird immer eine partialKlasse sein. Auf diese Weise können Sie eine zweite Teilklasse schreiben, die mit den erforderlichen Datenanmerkungen gekennzeichnet ist. In Ihrem Fall würde die Teilklasse folgendermaßen ItemRequestaussehen:

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;}

        //...
    }
}

11
Die Teilklasse wird nicht neu generiert. Das ist der Grund, warum es als partiell definiert wird.
MUG4N

Hast du den Teilmodifikator verpasst? Verwenden Sie denselben Namespace?
MUG4N

3
.NET Core-Benutzer: Verwenden Sie ModelMetadataType anstelle von MetadataType.
Bob Kaufman

1

40

Wie MUG4N beantwortet können Sie verwenden partielle Klassen aber besser genutzt werden Schnittstellen statt. In diesem Fall treten Kompilierungsfehler auf, wenn das EF-Modell nicht dem Validierungsmodell entspricht. So können Sie Ihre EF-Modelle ändern, ohne befürchten zu müssen, dass die Validierungsregeln veraltet sind.

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 Wenn Sie einen Projekttyp verwenden, der sich von ASP.NET MVC unterscheidet (wenn Sie eine manuelle Datenüberprüfung durchführen), vergessen Sie nicht, Ihre Prüfer zu registrieren

/* Global.asax or similar */

TypeDescriptor.AddProviderTransparent(
    new AssociatedMetadataTypeTypeDescriptionProvider(typeof(Entity), typeof(IEntityMetadata)), typeof(Entity));

@dimonser nette Lösung, ich habe versucht, auch solche XML-Kommentare hinzuzufügen (für jene DB-Felder, die eine kleine Erklärung im Code benötigen - dh in Intellitype angezeigt werden sollen), aber es scheint nicht zu funktionieren. Irgendeine Idee, wie das geht?
Percy

Hallo @Rick, Sie können eine Schnittstelleneigenschaft kommentieren, diese wird jedoch nur angezeigt, wenn Sie mit einer Schnittstellenvariablen arbeiten. Oder Sie können einen Kommentar in eine Teilklasse einfügen. In diesem Fall wird es angezeigt, wenn Sie mit einer Instanz Ihrer Klasse arbeiten. Keine anderen Fälle verfügbar. Sie können also beide verwenden, um alle Situationen abzudecken. Im ersten Fall können Sie
Feldvalidierungsregeln

Wirklich gut durchdachte Antwort, aber ich würde lieber Kompilierungsfehler sehen, wenn die Validierung nicht mehr mit der automatisch generierten Entity-Framework-Klasse synchronisiert ist. Ich habe Probleme, mir eine Situation vorzustellen, in der Sie möglicherweise eine Eigenschaft validieren möchten, die in Ihrer Entity-Framework-Klasse nicht mehr vorhanden ist.
Mike

1
Dies funktioniert nicht für mich, es heißt, ich muss die IEntityMetadata-Schnittstelle implementieren ...
Worthy7

14

Ich habe eine Lösung wie die Antwort von MUG4N gefunden , aber stattdessen die MetaDataKlasse innerhalb der Entitätsklasse verschachtelt , wodurch die Anzahl der Klassen in Ihrer öffentlichen Namespace-Liste verringert und die Notwendigkeit beseitigt wurde, für jede Metadatenklasse einen eindeutigen Namen zu haben.

using System.ComponentModel.DataAnnotations;

namespace MvcApplication1.Models 
{
    [MetadataType(typeof(MetaData))]
    public partial class ItemRequest
    {
        public class MetaData
        {
            [Required]
            public int RequestId;

            //...
        }
    }
}

Ich habe das überall in meinem Projekt verwendet. Viel einfacher zu organisieren. Ich füge auch benutzerdefinierte Eigenschaften [NotMapped]innerhalb der Teilklasse hinzu, wenn ich sie benötige.
Carter Medlin

5

Dies ist eine Art Erweiterung der Antwort von @dimonser. Wenn Sie Ihr Datenbankmodell neu generieren, müssen Sie die Schnittstellen für diese Klassen manuell neu hinzufügen.

Wenn Sie Magen dafür haben, können Sie auch Ihre .ttVorlagen ändern :

Hier ist ein Beispiel für die automatische Generierung von Schnittstellen in einigen Klassen. Dies ist ein Fragment aus der .ttErsetzungsmethode EntityClassOpeningin Ihrer Klasse durch Folgendes (und natürlich var stringsToMatchdurch Ihre Entitätsnamen und Schnittstellen).

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);
}

Kein normaler Mensch sollte sich das antun, es wurde in der Bibel bewiesen, dass man dafür in die Hölle geht.


2

Ich bin mir nicht sicher, wie ich tun soll, wonach Sie fragen, aber es gibt einen Weg, dies zu umgehen. Dynamische Datenüberprüfung durch Überschreiben der GetValidators Ihres benutzerdefinierten DataAnnotationsModelValidatorProvider. Darin können Sie die Regeln für die Validierung jedes Felds (aus einer Datenbank, einer Konfigurationsdatei usw.) lesen und nach Bedarf Validatoren hinzufügen. Es hat den zusätzlichen Wert, dass Ihre Validierung nicht mehr eng mit dem Modell verbunden ist und geändert werden kann, ohne dass die Site neu gestartet werden muss. Natürlich könnte es für Ihren Fall übertrieben sein, aber es war ideal für unseren!


Wir haben es getan, als wir diese Struktur zum ersten Mal implementiert haben. Wir sind inzwischen zu NHibernate gewechselt, aber dies hat keinen Einfluss auf die Lösung. Unser Validierungscode funktionierte unverändert (nur die Datenzugriffsschicht wurde geändert).
JTMon

1

Ändern Sie die T4-Vorlage, indem Sie die erforderlichen Anmerkungen hinzufügen. Diese Datei heißt normalerweise MODELNAME.tt

Finden Sie heraus, wo der T4 die Klasse und die Methoden erstellt, um zu wissen, wo diese abgelegt werden sollen.

     <#=codeStringGenerator.IgnoreJson(navigationProperty)#>


//create this method in file
public string IgnoreJson(NavigationProperty navigationProperty){
            string result = navigationProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? "" : @"[JsonIgnore]
    [IgnoreDataMember]";

            return result;
        }

Sie müssen auch die Namespaces hinzufügen.

<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using System.Runtime.Serialization;

Erstellen Sie Ihre Klassen neu, indem Sie Ihr Modell speichern. Alle Ihre Methoden sollten mit Anmerkungen versehen sein.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.