使用Entity Framework和Razor页面,我目前有一个系统,可以将我的模型包装到视图模型中并显示在屏幕上,我认为这是我在MVVM中要做的建筑。
但是,我在将类型'Foo'的列表强制转换为'FooView'时遇到了一些麻烦,但是将类型'Foo'的变量强制转换为'FooView'很好。这是代码:
学生班
public class Student
{
public Student()
{
Id = null;
FirstName = "";
Surname = "";
Age = 0;
DateOfBirth = new DateTime();
Results = new HashSet<Result>();
}
public Student(string firstName, string surname, DateTime dateOfBirth)
{
Id = null;
FirstName = firstName;
Surname = surname;
DateOfBirth = dateOfBirth;
Results = new HashSet<Result>();
}
public int? Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public int Age { get; private set; }
// Implement backing field
private DateTime _dateOfBirth;
public DateTime DateOfBirth
{
get => _dateOfBirth;
set
{
// Set Age when date of birth is provided
_dateOfBirth = value;
Age = (DateTime.Today.Year - this._dateOfBirth.Year);
if (_dateOfBirth.Date > DateTime.Today.AddYears(-this.Age)) this.Age--;
}
}
public HashSet<Result> Results { get; set; }
public static implicit operator StudentView(Student student)
{
return new StudentView(student);
}
}
成功将学生项目投射到剃须刀页面WORKS上的学生查看项目
@foreach (var item in Model.Result)
{
<tr>
<td>
@Html.DisplayFor(modelItem => ((StudentView)item.Student).FullName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Score)
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
尝试投射列表以键入“学生视图”失败
public async Task OnGetAsync()
{
Student = await _context.Student.Cast<StudentView>().ToListAsync();
}
InvalidCastException:无法转换类型的对象 键入“ StudentManagerDemoCore.Models.Student” 'StudentManagerDemoCore.ViewModels.StudentView'。
StudentManagerDemoCore.Pages.Teacher.ManageStudent.IndexModel.OnGetAsync() 在Index.cshtml.cs
Student = await _context.Student.Cast<StudentView>().ToListAsync();
我感觉这里缺少一些东西,但是我不确定是什么。该错误表明我的投射方法存在问题,但这并不能解释为什么有时会起作用。
有人知道我要去哪里吗?
答案 0 :(得分:3)
您可以通过多种方法来解决问题。
第一个解决方案是手动执行以下操作:
await _context.Student.Select(student => new StudentView()
{
Id = student.Id,
//....
}
另一种解决方案是拥有一个手动映射器来执行映射。静态函数,它使用Student
并将其转换为StudentView
并返回它。您可以在其他地方重用它。
我建议的最佳解决方案是使用AutoMapper。
答案 1 :(得分:1)
摘自MSDN(我的重点):
此方法的源序列是IEnumerable,这意味着元素具有对象的编译时静态类型。 此方法执行的唯一类型转换是引用转换和拆箱转换。集合中元素的运行时类型必须与目标类型匹配,或者在值类型的情况下,元素的运行时类型必须是目标类型的装箱转换的结果。不允许使用其他转换类型,例如不同数字类型之间的转换。
因此,对于您的特定情况,在Student
和StudentView
之间定义隐式转换时,请执行以下操作:
public async Task OnGetAsync()
{
Student = await _context.Student.Select(x=>(StudentView)x).ToListAsync();
}
答案 2 :(得分:0)
我也通过在'StudentView'类中实现了从'StudentView'到'Student'的转换,然后使用磁控管解决方案,设法解决了这个问题。
因此,我在“视图”类中实现了转换。为什么我不知道为什么需要这样做,对我来说似乎很神奇,因为对于“学生”到“ StudentView”的转换来说,这种转换是不必要的。也许某处写的东西出于某种原因需要双向转换。
public class StudentView : ViewBase<Student>
{
// Removed for brevity
public static implicit operator Student(StudentView student)
{
return new Student(student);
}
}
然后更新了铸造方法,就像磁控管突出显示的那样:
public async Task OnGetAsync()
{
Student = await _context.Student.Select(x => (StudentView)x).ToListAsync();
}
我还想强调Billybob的答案,因为他提供了另一种解决问题的正确方法,我只是选择了另一种方法。