是否有理由在 Blazor 服务器端使用 ViewModel?
Is there a reason to use ViewModel in Blazor Server Side?
我开始开发 Blazor 服务器端应用程序,我的想法是使用:
- 功能文件夹结构(参见 https://medium.com/c2-group/simplifying-projects-with-a-folder-by-feature-structure-3a13cff2d28c)
- 垂直切片架构(参见 https://jimmybogard.com/vertical-slice-architecture/)。事实上,我将使用 MediatR 库使用 CQRS 模式。
我的文件夹结构如下所示:
Features
Feature 1
XXXView.razor : the view
XXXView.razor.cs : the partial class
XXXView.razor.queries.cs : contains the queries (ex : GetCustomer) used by the view
XXXView.razor.commands.cs : contains the commands (ex : SaveCustomer) used by the view
Feature 2
我的问题如下:在这种架构中,是否有充分的理由使用 ViewModel(如 asp .net MVC 项目)而不是直接在视图中使用实体?
下面的代码是我在不使用 ViewModel 的情况下会做什么的示例。
public partial class UserEditView : EditableComponentBase
{
[Parameter]
public long? Id { get; set; }
[Required]
public string Name { get; set; }
protected override async Task OnInitializedAsync()
{
if (this.Id.HasValue)
{
UserEntity user = await Mediator.Send(new GetUserQuery(this.Id.Value));
this.Name = user.Name;
this.Title = $"Change info of {user.Name}";
}
else
{
this.Title = "New user";
}
await base.OnInitializedAsync();
}
protected override async Task Save()
{
UserEntity user = this.Id.HasValue ? await Mediator.Send(new GetUserEditViewQuery(this.Id.Value)) : new UserEntity();
user.Nom = this.Name;
await Mediator.Send(new SaveUserCommand(user));
Close();
}
}
使用 GetUserEditViewQuery return使用获取或延迟加载所需的所有信息创建实体。
下面的代码是我使用 ViewModel 时会做什么的示例。
public partial class UserEditView : EditableComponentBase
{
[Parameter]
public long? Id { get; set; }
public UserViewModel User { get; set; } = new UserViewModel();
protected override async Task OnInitializedAsync()
{
if (this.Id.HasValue)
{
this.User = await Mediator.Send(new GetUserEditViewQuery(this.Id.Value));
this.Title = $"Change info of {this.User.Name}";
}
else
{
this.Title = "New user";
}
await base.OnInitializedAsync();
}
protected override async Task Save()
{
await Mediator.Send(new SaveUserCommand(user));
Close();
}
}
使用 GetUserEditViewQuery return创建包含所有所需信息的 ViewModel。
如您所见,如果我不使用 ViewModel,不同之处在于视图 :
- 定义将自行显示的字段(不使用 ViewModel)
- 使用查询获取数据,这里 return 是一个实体(但如果需要,可以 return 其他东西)然后使用它来设置变量
- 将变量转换为实体(或其他对象,如果需要)并调用命令保存信息
=> 这看起来与我开发桌面应用程序的方式非常相似
我会对每种方法的优缺点感兴趣。
更新
@Henk Holterman:我将示例 2 的 GetUserQuery 更改为 GetUserEditViewQuery
@Ben Sampica:首先,感谢您的回答。
如果我理解正确的话,
在“更改用户信息”用例中,ViewModel (UserEditViewModel) 将包含编辑用户所需的所有信息。
在“查看用户信息”用例中,ViewModel(UserViewViewModel:不是很好但是......)将包含查看用户所需的所有信息(可能与更改页面不同)。
=> 查询不同,因此 return 不同的 ViewModel。
我明白了,很有道理。
但是页面只有一个 ViewModel 还是我可以使用多个?
实际上,在某些情况下,页面包含带有按钮的列表,允许用户在此列表中添加元素。
对我来说,在列表中添加一个元素将调用一个新查询,该查询将元素添加到数据库中,然后刷新列表。
在很多示例中,我看到人们在页面的 ViewModel(比如 UserEditViewModel)中创建了一个 属性 并将其填充到主查询(比如 GetUserEditViewQuery)中,这在这里实际上是不可能的。
如果我必须这样做,我肯定会这样做:
this.List = await Mediator.Send(new GetListForUserEditViewQuery());
this.User = await Mediator.Send(new GetUserEditViewQuery());
是否正确?
垂直切片架构的部分框架是具有架构。通过将您的域直接耦合到您的演示文稿,当不同的视图需要不同的东西时,您就会面临问题。您的 GetUserQuery
根本不应该是那样,它应该是 GetUserEditViewQuery
视图需要的东西 - 用户、标题等。垂直切片是关于 用例 , 在这种情况下,一个人需要查看有关用户的所有可编辑信息。
您的查询应该 return 一个 ViewModel/DTO 表示使用该视图返回视图。
如果您可以绝对肯定永远不会出现这种情况 - 当然,请直接使用用户。
我开始开发 Blazor 服务器端应用程序,我的想法是使用:
- 功能文件夹结构(参见 https://medium.com/c2-group/simplifying-projects-with-a-folder-by-feature-structure-3a13cff2d28c)
- 垂直切片架构(参见 https://jimmybogard.com/vertical-slice-architecture/)。事实上,我将使用 MediatR 库使用 CQRS 模式。
我的文件夹结构如下所示:
Features
Feature 1
XXXView.razor : the view
XXXView.razor.cs : the partial class
XXXView.razor.queries.cs : contains the queries (ex : GetCustomer) used by the view
XXXView.razor.commands.cs : contains the commands (ex : SaveCustomer) used by the view
Feature 2
我的问题如下:在这种架构中,是否有充分的理由使用 ViewModel(如 asp .net MVC 项目)而不是直接在视图中使用实体? 下面的代码是我在不使用 ViewModel 的情况下会做什么的示例。
public partial class UserEditView : EditableComponentBase
{
[Parameter]
public long? Id { get; set; }
[Required]
public string Name { get; set; }
protected override async Task OnInitializedAsync()
{
if (this.Id.HasValue)
{
UserEntity user = await Mediator.Send(new GetUserQuery(this.Id.Value));
this.Name = user.Name;
this.Title = $"Change info of {user.Name}";
}
else
{
this.Title = "New user";
}
await base.OnInitializedAsync();
}
protected override async Task Save()
{
UserEntity user = this.Id.HasValue ? await Mediator.Send(new GetUserEditViewQuery(this.Id.Value)) : new UserEntity();
user.Nom = this.Name;
await Mediator.Send(new SaveUserCommand(user));
Close();
}
}
使用 GetUserEditViewQuery return使用获取或延迟加载所需的所有信息创建实体。
下面的代码是我使用 ViewModel 时会做什么的示例。
public partial class UserEditView : EditableComponentBase
{
[Parameter]
public long? Id { get; set; }
public UserViewModel User { get; set; } = new UserViewModel();
protected override async Task OnInitializedAsync()
{
if (this.Id.HasValue)
{
this.User = await Mediator.Send(new GetUserEditViewQuery(this.Id.Value));
this.Title = $"Change info of {this.User.Name}";
}
else
{
this.Title = "New user";
}
await base.OnInitializedAsync();
}
protected override async Task Save()
{
await Mediator.Send(new SaveUserCommand(user));
Close();
}
}
使用 GetUserEditViewQuery return创建包含所有所需信息的 ViewModel。
如您所见,如果我不使用 ViewModel,不同之处在于视图 :
- 定义将自行显示的字段(不使用 ViewModel)
- 使用查询获取数据,这里 return 是一个实体(但如果需要,可以 return 其他东西)然后使用它来设置变量
- 将变量转换为实体(或其他对象,如果需要)并调用命令保存信息 => 这看起来与我开发桌面应用程序的方式非常相似
我会对每种方法的优缺点感兴趣。
更新 @Henk Holterman:我将示例 2 的 GetUserQuery 更改为 GetUserEditViewQuery
@Ben Sampica:首先,感谢您的回答。 如果我理解正确的话, 在“更改用户信息”用例中,ViewModel (UserEditViewModel) 将包含编辑用户所需的所有信息。 在“查看用户信息”用例中,ViewModel(UserViewViewModel:不是很好但是......)将包含查看用户所需的所有信息(可能与更改页面不同)。 => 查询不同,因此 return 不同的 ViewModel。
我明白了,很有道理。
但是页面只有一个 ViewModel 还是我可以使用多个? 实际上,在某些情况下,页面包含带有按钮的列表,允许用户在此列表中添加元素。 对我来说,在列表中添加一个元素将调用一个新查询,该查询将元素添加到数据库中,然后刷新列表。
在很多示例中,我看到人们在页面的 ViewModel(比如 UserEditViewModel)中创建了一个 属性 并将其填充到主查询(比如 GetUserEditViewQuery)中,这在这里实际上是不可能的。 如果我必须这样做,我肯定会这样做:
this.List = await Mediator.Send(new GetListForUserEditViewQuery());
this.User = await Mediator.Send(new GetUserEditViewQuery());
是否正确?
垂直切片架构的部分框架是具有架构。通过将您的域直接耦合到您的演示文稿,当不同的视图需要不同的东西时,您就会面临问题。您的 GetUserQuery
根本不应该是那样,它应该是 GetUserEditViewQuery
视图需要的东西 - 用户、标题等。垂直切片是关于 用例 , 在这种情况下,一个人需要查看有关用户的所有可编辑信息。
您的查询应该 return 一个 ViewModel/DTO 表示使用该视图返回视图。
如果您可以绝对肯定永远不会出现这种情况 - 当然,请直接使用用户。