1

MeterPeak エンティティがあり、このエンティティには外部キーとして MeterReading エンティティがあります (質問の下部に含まれています)。MeterReading エンティティには、MeterSiteId と DateTime で構成される複合主キーがあります。

したがって、MeterPeak エンティティでは、既存の MeterReading エンティティと一致する MeterSiteId と DateTime を入力して、外部キー制約を満たす必要があることを理解しています。存在しない外部キーへのリンクは許可されるべきではありません。

ただし、MeterPeakController の編集アクションには、次のコードがあります。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(MeterPeak meterpeak)
    {
        if (ModelState.IsValid)
        {
            unitOfWork.MeterPeakRepository.Update(meterpeak);
            unitOfWork.Save();
            return RedirectToAction("Index");
        }
        ViewBag.MeterSiteId = new SelectList(unitOfWork.MeterSiteRepository.Get(b => true), "Id", "Location", meterpeak.MeterSiteId);
        return View(meterpeak);
    }

既存の検針値と一致しない MeterSiteId と DateTime を入力して保存しようとすると、ModelState.IsValid チェックが false を返すことを期待しますが、そうではありません。unitOfWork.save() 行に到達したときにのみ失敗し、このエラーで dbcontext への変更を保存するときにエラーが発生します

The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_dbo.MeterPeaks_dbo.MeterReadings_MeterSiteId_DateTime"

dbcontext.save に到達する前に ModelState.IsValid がこの問題を検出しないのはなぜですか?

public class MeterPeak
{
    [Key]
    public int Id { get; set; }

    [ForeignKey("PeakReading"), Column(Order = 1)]
    public int MeterSiteId { get; set; }

    [ForeignKey("PeakReading"), Column(Order = 2)]
    public DateTime DateTime { get; set; }

    public int? Rating { get; set; }

    public String Note { get; set; }

    public virtual MeterReading PeakReading { get; set; }
}

public class MeterReading
{
    [Key, Column(Order = 1)]
    [Required(ErrorMessage = "Please Select a Meter Site")]
    public int MeterSiteId { get; set; }

    [Key, Column(Order = 2)]
    [Required]
    public DateTime DateTime { get; set; }

    //This is not the Primary key but I need one unique value to assist in getting records, especially from Javascript
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid SingleKey { get; set; }

    public virtual MeterSite MeterSite { get; set; }

    [Required]
    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double RawLevel { get; set; }

    [Required]
    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double RawVelocity { get; set; }

    [Required]
    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double RawFlow { get; set; }

    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double ValidLevel { get; set; }

    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double ValidVelocity { get; set; }

    [DisplayFormat(DataFormatString = "{0:#,##0.00000#}", ApplyFormatInEditMode = true)]
    public Double ValidFlow { get; set; }

    [Range(-1, 3, ErrorMessage = "Rating must be one of the following -1,0,1,2,3")]
    public int Rating { get; set; }

    public bool? Valid { get; set; }

    public virtual ICollection<Note> Notes { get; set; }

}
4

1 に答える 1

6

dbcontext.save に到達する前に ModelState.IsValid がこの問題を検出しないのはなぜですか?

これModelStateは ASP.NET MVC の概念であり、データベースに関する知識はありません。ModelStateプロパティは、HTTP ポストでアクション メソッドに渡される情報の状態を表します。正常に動作しています。

フォームは表示されていませんが、Editアクション メソッドが を受け入れるので、MeterPeakHTTP ポストで次の値が送信されていると想定しています: IdMeterSiteIdDateTime、および(ブラウザ)。RatingNotePeakReading

ASP.NET MVC はこれらの値を取得し、モデル バインダーをMeterPeak使用して、送信された値を使用してオブジェクトを構築します。

次に、指定した値を使用して、オブジェクトに存在する検証属性に対して、またはValidateオブジェクトがインターフェイスを実装している場合はメソッドを呼び出すことによって、オブジェクトが検証されIValidatableObjectます。

オブジェクトは、検証属性でプロパティを装飾したり、インターフェイスを実装したりしないため、プロパティが trueである理由を説明する検証MeterPeak対象がないことに注意してください。(適用した属性は、クラスをデータベース テーブルにマップする方法を理解するために Entity Framework によって使用されます)。IValidatableObjectModelState.IsValid

要約すると:

  1. HTTP 投稿を行う
  2. MVC はポストされた値を取得し、モデル バインダーを使用してMeterPeakオブジェクトを構築します。
  3. オブジェクトは上記のルールを使用して検証され、アクション メソッドに渡されます。

データベース呼び出しはまだ行われていないため、この時点で外部キー制約に違反していることを MVC が認識する方法はありません

余談ですが、エンティティを ASP.NET MVC アプリケーション コントローラーの「モデル」として使用しないことをお勧めします。実際に必要なのは、ビュー固有のモデル (viewModel) であり、コントローラーで (手動で、またはAutoMapperなどのフレームワークを使用して) エンティティに変換されます。これは大変な作業のように聞こえるかもしれませんが、最終的には報われます。モデルごとに viewModel を必要としないようにする方法についての質問への回答に、いくつかの利点が示されています。さらなる議論は、TryUpdateModel、ASP .NET MVC 3 の実際の例という質問で利用できます。

于 2013-05-09T16:59:48.233 に答える