6

状況

3 つの列を含むテーブルを持つ LINQ-TO-SQL モデルがあります。通常のID (ID、自動生成)、次にintの Avarchar(MAX)型のB。データベースでは、すべての列がNOT NULLとして定義されています。

WebFormsページで、アイテムにバインドする DetailsView を宣言しました。

<asp:ValidationSummary runat="server" ShowModelStateErrors="true" />
<asp:DetailsView DataKeyNames="Id" runat="server" ItemType="test.MyTable"
    SelectMethod="..." UpdateMethod="...">
      <Fields>
        <asp:DynamicField DataField="A" />
        <asp:TemplateField>
            <EditItemTemplate>
                <asp:TextBox ID="B" runat="server" TextMode="MultiLine" Columns="80" Rows="8" Text="<%# BindItem.B %>" />
            </EditItemTemplate>
            <ItemTemplate>
                <pre><asp:Label runat="server" Text="<%# Item.B %>"  /></pre>
            </ItemTemplate>
        </asp:TemplateField>
      </Fields>
</asp:DetailsView>

このコードはすべて、ASP.NET 4.5 上の Visual Studio 2012 で実行されます。

何が起こるのですか

ここまでは順調ですね。作品の更新と閲覧。無効な値を入力すると、問題が発生します。フィールドAに "" を使用すると、ページの上部に適切なエラー メッセージが表示されます。わーい!ただし、フィールドBの値として "" を使用すると、次のようになります。

    public void DetailsView_UpdateItem(int id)
    {
      var item = db.MyTable.Where(row => row.Id==id).Single();
      TryUpdateModel(item);
      if (ModelState.IsValid)
        db.SubmitChanges();
    }
  1. UpdateItem メソッドが呼び出されます
  2. TryUpdateModel が機能し、フォームの値をitemに入力します。
  3. デバッグすると、予想どおりitem.Bnullであることがわかります
  4. その後、ModelState.IsValidはtrueを返します?!?
  5. db.SubmitChanges()の呼び出しが例外で失敗する

問題

データ モデルでBをnullにできないと指定したときに、 ModelState.IsValidがtrueを返す理由がわかりません。誰か説明できますか?私は何を間違っていますか?

回避策

私が試したことの 1 つは、次のコードを含めて、データ クラスにデータ注釈を追加することでした。うまくいきませんでした。

  [MetadataType(typeof(MyTableMetadata))]
  public partial class MyTable
  {
  }

  public class MyTableMetadata
  {
    [Required]
    [StringLength(255,MinimumLength=1)]
    public string B { get; set; }
  }

UpdateItemメソッドで手動でnullをチェックしたり、RequiredFieldValidator を追加したりできることは明らかですが、私はそうしたくないでしょう。

4

4 に答える 4

1

null 値を取得しているのはなぜだと思いますか? 空の文字列は null と同等ではありません。あなたが提案したように、nullを手動でチェックすることでこれを確認できます。

を追加しStringLengthAttributeて、null 以外の制約に加えて空でない制約を適用できます。

于 2012-09-11T09:18:29.300 に答える
1

TryUpdateModel() メソッドは基本的に (大幅に簡略化)、モデル クラスのフィールド/プロパティの名前を使用して、投稿のフォーム コレクションで投稿された値を探します。テキストボックスに ID = B を指定した asp.net グリッドの場合、コントロールの名前は ctl00$B のようになります。モデル バインダーは、フォーム コレクションがポストに存在していても、ドットを接続してフォーム コレクションから値を取得することはできません。

編集可能なフィールドに「asp:BoundField」を使用すると、問題が解決する可能性があると思います。カスタム モデル バインダーを作成するか、自分で値を割り当てることも検討してください。モデル内のプロパティの名前を、生成されたコントロールの名前と一致するように変更することも、問題を解決する別の方法です (ただし、このオプションは選択しないでください)。

TryUpdateModel() は、投稿で値を見つけたがモデルの型に値をキャストできなかった場合に false を返します。それ以外の場合は true を返します。

于 2012-09-12T18:26:05.113 に答える
1

任意の提案: System.ComponentModel.DataAnnotations 3.5 を参照していることを確認してください。(3.6ではない)またはそのための他の正しい名前空間(私が入手した限りでは、WCF RIAサービス専用のものがあります)。[DisplayFormat(ConvertEmptyStringToNull = ... )] の別の設定を試してください POST リクエストを実行していることを確認してください =)

于 2012-09-07T09:39:54.850 に答える
0

public class SecurityLayer { StringBuilder SB = new StringBuilder();

    public string SecurityValidate(object OBJ)
    {
        SB.Clear();
        var context = new ValidationContext(OBJ, serviceProvider: null, items: null);
        var results = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(OBJ, context, results);

        if (!isValid)
        {
            foreach (var validationResult in results)
            {
                //    Console.WriteLine(validationResult.ErrorMessage);
                SB.AppendLine(validationResult.ErrorMessage);
            }
        }

        return (SB.Length == 0 ? "SUCCESS" : SB.ToString());
    }
}
于 2013-09-28T12:08:42.210 に答える