2

私は EF 4.5 と DbContext を使用しています。ビジネス ルール レイヤー レベルでは、一部のエンティティ シナリオでエンティティ値のプロパティを変更しないようにチェックを実装する必要があります。サンプル:他のステータスでないStartProjecteDate場合は読み取り専用にする必要があります。ProjectIsStarted

私はDRY原則に従います。このため、コンテキストと UI から読み取り専用プロパティ リストを検査できるはずです。

私の質問:

プロパティを動的に読み取り専用に設定できる DataAnnotation バリデーターはありますか?

(そうでない場合、この問題に対する別の/より良い解決策はありますか?)

私は Web フォーム (および Telerik) アーキテクチャを扱っていることに注意してください。クリーンでエレガントなパターンを歓迎します。

Jesse Webbが説明しているように、実行時に EditableAttribute を設定および取得しようとしていますが、プロパティ、私のコードから dataannotation 属性を取得できません:

<EditableAttribute(False)>
<MaxLength(400, ErrorMessage:="Màxim 400 caracters")>
Public Property NomInvertebrat As String

ここに画像の説明を入力

ドキュメントを掘り下げた後、2013 年 11 月 8 日に編集されました。おそらく、iReadonlyableProperties インターフェイスが 1 つの方法である可能性があります。

4

3 に答える 3

1

.NET では、System.ComponentModel.ICustomTypeDescriptor を実装することにより、クラスの構造を動的に変更できます。ほとんどのシリアライザーは、このインターフェイスをサポートしています。

// Sample Serialization

foreach(PropertyDescriptor p in TypeDescriptor.GetProperties(obj)){
    string name = p.PropertyName;
    object value = p.GetValue(obj);
}

内部的に TypeDescriptor は Reflection を使用しますが、実装により、リフレクション属性を簡単にオーバーライドできます。

実装の 3 つのステップを次に示します。

// Implement System.ComponentModel.ICustomTypeDescriptor Interface on
// your Entity

public class MyEntity: System.ComponentModel.ICustomTypeDescriptor
{
     ....
     // most methods needs only call to default implementation as shown below

    System.ComponentModel.AttributeCollection      
    System.ComponentModel.ICustomTypeDescriptor.GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    string System.ComponentModel.ICustomTypeDescriptor.GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    string System.ComponentModel.ICustomTypeDescriptor.GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }

    System.ComponentModel.TypeConverter System.ComponentModel.ICustomTypeDescriptor.GetConverter()
    {
        return TypeDescriptor.GetConverter(this, true);
    }

    System.ComponentModel.EventDescriptor System.ComponentModel.ICustomTypeDescriptor.GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(this, true);
    }

    System.ComponentModel.PropertyDescriptor System.ComponentModel.ICustomTypeDescriptor.GetDefaultProperty()
    {
        return TypeDescriptor.GetDefaultProperty(this, true);
    }

    object System.ComponentModel.ICustomTypeDescriptor.GetEditor(Type editorBaseType)
    {
        return TypeDescriptor.GetEditor(this, editorBaseType, true);
    }

    System.ComponentModel.EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }

    System.ComponentModel.EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
    {
        return TypeDescriptor.GetEvents(this, true);
    }

    System.ComponentModel.PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
    {
        return TypeDescriptor.GetProperties(this, attributes, true);
    }

    object System.ComponentModel.ICustomTypeDescriptor.GetPropertyOwner(System.ComponentModel.PropertyDescriptor pd)
    {
        return this;
    }

    // The Only method that needs different implementation is below
    System.ComponentModel.PropertyDescriptorCollection 
    System.ComponentModel.ICustomTypeDescriptor.GetProperties()
    {
       // ... you are supposed to create new instance of 
       // PropertyDescriptorCollection with PropertyDescriptor

       PropertyDescriptorCollection pdc = new PropertyDescriptorCollection();

       foreach(PropertyDescriptor p in TypeDescriptor.GetProperties(this,true)){
            // if readonly..

            AtomPropertyDescriptor ap = new AtomPropertyDescriptor(p, p.Name);
            // or
            AtomPropertyDescriptor ap = new AtomPropertyDescriptor(p, p.Name, 
                true,
                new XmlIgnoreAttribute(),
                new ScriptIgnoreAttribute(),
                new ReadOnlyAttribute());
            pdc.Add(ap);
       }

       return pdc;
    }
}


// And here is the AtomPropertyDescriptorClass

public class AtomPropertyDescriptor : PropertyDescriptor
{
    PropertyDescriptor desc;

    bool? readOnly = null;

    public AtomPropertyDescriptor(PropertyDescriptor pd, string name, 
        bool? readOnly, params Attribute[] attrs) :
        base(name, attrs)
    {
        desc = pd;
        this.readOnly = readOnly;
    }

    public override bool CanResetValue(object component)
    {
        return desc.CanResetValue(component);
    }

    public override Type ComponentType
    {
        get
        {
            return desc.ComponentType;
        }
    }

    public override object GetValue(object component)
    {
        return desc.GetValue(component);
    }

    public override bool IsReadOnly
    {
        get
        {
            if (readOnly.HasValue)
                return readOnly.Value;
            return desc.IsReadOnly;
        }
    }

    public override Type PropertyType
    {
        get { return desc.PropertyType; }
    }

    public override void ResetValue(object component)
    {
        desc.ResetValue(component);
    }

    public override void SetValue(object component, object value)
    {
        desc.SetValue(component, value);
    }

    public override bool ShouldSerializeValue(object component)
    {
        return desc.ShouldSerializeValue(component);
    }
}
于 2013-11-13T19:31:36.570 に答える