如果您熟悉 blazor,您就會知道 EditForm 組件*需要提供給它們的模型。在這種情況下,提供的 ViewModel 用于創建新物體和從資料庫中提取的現有物體。在一種情況下,ViewModel 具有 Id == null 和另一種情況,它具有現有物體的 Id。創建 ViewModel 的最佳方法是什么?
一個可能是兩個建構式:
public class PersonViewModel
{
public PersonViewModel(String name, Int32 age)
{
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
Name = name;
Age = age;
}
public PersonViewModel(Guid id, String name, Int32 age)
{
if (id == Guid.Empty) throw new InvalidOperationException($"{nameof(id)} is invalid");
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
Id = id;
Name = name;
Age = age;
}
public Guid? Id { get; }
public String Name { get; }
public Int32 Age { get; }
}
這里有重復驗證作為一個問題。
另一種方法是使用兩種不同的靜態方法并將建構式設為私有,這會引入一些缺點,例如您將無法繼承類并使用基建構式:
public class PersonViewModel
{
private PersonViewModel() { }
public Guid? Id { get; private set; }
public String Name { get; init; }
public Int32 Age { get; init; }
public static PersonViewModel MakeWithoutId(String name, Int32 age)
{
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
return new()
{
Name = name,
Age = age,
};
}
public static PersonViewModel MakeWithId(Guid id, String name, Int32 age)
{
if (id == Guid.Empty) throw new InvalidOperationException($"{nameof(id)} is invalid");
var vm = PersonViewModel.MakeWithoutId(name, age);
vm.Id = id;
return vm;
}
}
我想有人可能會說將 id 作為私有集而不是 init 是不好的,我可以再次從頭開始初始化它,但通過這種方式,我重用了前一種方法的代碼和驗證。或者我應該有兩個單獨的 ViewModel 類,其中一個繼承或包含另一個,如 NewPersonViewModel 和 ExistingPersonViewModel?
- 現在我想到了 EditForm 輸入中使用的屬性應該有公共集,抱歉我在隨機檔案中嘗試這段代碼的錯誤
uj5u.com熱心網友回復:
這不是使用 EditForm 的方式......
您應該創建一個簡單的 POCO 類,無需任何型別的驗證。在 EditForm 中使用 DataAnnotation 驗證或 Fluent 驗證。
下面的代碼片段演示了如何使用資料庫中的資料初始化模型物件,以及如何為新條目添加模型類的新實體。
評論.cs
public class Comment
{
public string ID { get; set; }
public string Name { get; set; }
[MaxLength(100)]
public string Text { get; set; }
}
Index.razor
<p>Leave a message if you liked my answer</p>
<EditForm EditContext="@EditContext" OnValidSubmit="@HandleValidSubmit"
OnInvalidSubmit="@HandleInvalidSubmit">
<div class="alert @StatusClass">@StatusMessage</div>
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="name">Name: </label>
<InputText Id="name" Class="form-control" @bind-
Value="@Model.Name"></InputText>
<ValidationMessage For="@(() => Model.Name)" />
</div>
<div class="form-group">
<label for="body">Text: </label>
<InputTextArea Id="body" Class="form-control" @bind-
Value="@Model.Text"></InputTextArea>
<ValidationMessage For="@(() => Model.Text)" />
</div>
<button type="submit">Ok</button>
</EditForm>
code
{
private string StatusMessage;
private string StatusClass;
private EditContext EditContext;
private Comment Model;
protected override void OnInitialized()
{
// Here you put code from the database that instantiate the
// Model object, and populate it with data from external store
// You then instantiate the EditContext object pssing it the
// created model object. Now the data from the database is
// displayed in the form.
EditContext = new EditContext(Model);
base.OnInitialized();
}
protected void HandleValidSubmit()
{
// HandleValidSubmit is called when the user click the "submit"
// button. You can put here code that update the data in the
// data store, and then instantiate the EditContext object with
// a new model instance, which may be a new record from the
// database or a new empty instance of the model object; in our
// code it is the Comment class.
// Here's a code snippet demonstrating how to reset your form,
// to enable a new entry of comment:
// Model = new Comment();
// EditContext = new EditContext(Model);
// That is the way to ensure that
// your EditContext (Not EditForm) contains a new model object
// with default values. This is the heart of my answer to the
// issue you were facing. If it not clear, please ask...
StatusClass = "alert-info";
StatusMessage = DateTime.Now " Handle valid submit";
}
protected void HandleInvalidSubmit()
{
StatusClass = "alert-danger";
StatusMessage = DateTime.Now " Handle invalid submit";
}
}
不,我明白了,所以關鍵是我不應該關心當我重置表單或提供新模型時 Id 是默認值,因此例如在 Guids 的情況下是 Guid.Empty,在那個時間點。而且我不應該用不同的實體化方法使我自己復雜化。但是,如果我將“評論”作為物體,我應該在 blazor 專案中將其稱為 CommentViewModel 嗎?或者我應該每個組件/視圖只有一個視圖模型?
我覺得很難理解這個評論。但是,這是我的輸入:
您可以根據需要命名您的視圖模型。我認為您不必同時定義視圖模型和模型,這尤其取決于模型的復雜性,以及您是否必須使用業務邏輯,在這種情況下,您應該定義視圖模型,但肯定不會執行您在PersonViewModel課堂上進行的各種驗證。您的視圖模型不應成為傳統的物體物件,您應該通過使用 DataAnnotations 或 Fluent 驗證來執行欄位驗證。
uj5u.com熱心網友回復:
使用 private set; 在視圖模型是不是非常有用。
ViewModel在編輯后需要驗證,而不是在創建時驗證。并且您希望 Validation 為用戶反饋產生明確的資訊,而不是例外。
我會選擇:
public class PersonViewModel
{
public PersonViewModel() { } // can be omitted
public Guid? Id { get; set; } // never validate (in a VM)
public String Name { get; set; } // use DataAnnotations or s.e.
// ...
public string[] Validate() { ... }
}
您嘗試應用的邏輯適用于物體,您應該防止創建無效的物體。
uj5u.com熱心網友回復:
我會將驗證代碼移到更靠近屬性的地方,這樣您也可以使用公共設定器。
public class PersonViewModel
{
private Guid? _id;
private string _name;
private int _age;
public Guid? Id
{
get { return _id; }
set
{
if (value == Guid.Empty) throw new InvalidOperationException($"{nameof(value)} is invalid");
_id = value;
}
}
public string Name
{
get { return _name; }
set
{
if (String.IsNullOrWhiteSpace(value)) throw new InvalidOperationException($"{nameof(value)} is invalid");
_name = value;
}
}
public int Age
{
get { return _age; }
set
{
if (value < 0) throw new InvalidOperationException($"{nameof(value)} is invalid");
_age = value;
}
}
public PersonViewModel(String name, Int32 age)
{
Name = name;
Age = age;
}
public PersonViewModel(Guid id, String name, Int32 age)
{
Id = id;
Name = name;
Age = age;
}
public static PersonViewModel GetInstance(String name, Int32 age)
{
return new PersonViewModel(name, age);
}
public static PersonViewModel GetInstance(Guid id, String name, Int32 age)
{
return new PersonViewModel(id, name, age);
}
}
測驗
var pvm=PersonViewModel.GetInstance("New Name", 20); //ok
var pvm1=PersonViewModel.GetInstance(Guid.NewGuid(), "New Name", -1); //invalid age exception
我提出了一個例外,因為您想要它如果您只需要用戶驗證,只需使用資料注釋或流暢的驗證。
或者你可以創建屬性來顯示錯誤訊息,像這樣
public string AgeErrorMessage {get; private set;}
public int Age
{
get { return _age; }
set
{
if (value < 0) AgeErrorMessage=$"{nameof(value)} is invalid";
else
{
AgeErrorMessage=string.Empty;
_age = value;
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/363115.html
