在不同命名空间的基类上使用属性和元数据
本文关键字:属性 元数据 基类 命名空间 | 更新日期: 2023-09-27 18:02:37
我有一个单独的Visual Studio项目,在那里我保留了我的数据模型(EF6)。因此,我的实体位于名称空间Name1
中(首先由EF6数据库创建,但在本例中进行了简化):
namespace Name1
{
public class Person
{
public string FName {get; set;}
public string LName {get; set;}
}
}
现在,我已经创建了一个新的MVC 5项目,它引用了data Visual Studio项目,以便我可以访问实体。在我的MVC项目中,我想像这样向实体添加一些元数据:
namespace NameMvc
{
[MetadataType(typeof(PersonMetaData))]
public class Person : Name1.Person
{
}
public class PersonMetaData
{
[Display(Name = "Firstname")]
public string FName;
}
}
在我的控制器中,我想获取所有的person,所以我有一个这样的Action:
using Name1;
using NameMvc;
-- controller class code
public ActionResult Index()
{
var persons = db.Person.ToList();
return View(persons);
}
-- controller class code
在我看来,我试图通过:
访问它@model IEnumerable<NameMvc.Person>
现在,当我运行代码时,我得到一个错误:
传入字典的模型项的类型为'System.Data.Entity.Infrastructure.DbQuery ' 1[Name1. name]。,但是这个字典需要一个类型为'System.Collections.Generic.IEnumerable ' 1[Name.MvcPerson]'的模型项。
我可能在操作中做错了什么,因为db.Person
来自Name1
命名空间。
我想在我的视图中使用元数据,以便当我做这样的@Html.DisplayNameFor(model => model.FName)
时,它显示"Firstname"
你得到一个错误渲染你的视图,因为你从你的动作返回IEnumerable<Name1.Person>
,但你的视图期待IEnumerable<NameMvc.Person>
。当您在视图中使用强类型模型时,它必须与操作返回的模型匹配。
这个错误有两种可能的解决方案:
- 更改视图以使用
IEnumerable<Name1.Person>
作为其模型,或 - 改变你的动作,返回一个
IEnumerable<NameMvc.Person>
作为模型。
当您使用MetadataType
向您的模型添加元数据时,最常见的方法是使用原始模型类作为部分类生成的事实。您为分部类创建另一个"部分",并向其添加MetadataType
属性。
但是,分部类不能跨程序集使用。因此,这意味着如果您将模型移动到它自己的程序集中,那么您就不能将部分类添加到MVC项目中以添加元数据。
要解决这个问题,可以执行以下操作之一:
- 在模型的程序集中添加元数据。为此,您可以在模型的程序集中使用部分类解决方案。这样做的问题是,你现在混合了视图逻辑和数据逻辑。
- 在MVC项目中创建一个新类,它是数据模型的伪副本,用作视图模型。将元数据添加到其中。你的动作会返回这个视图模型你的视图会使用它。在您的操作中,您将数据从数据模型复制到视图模型。
我更喜欢选项#2,原因如下:
- 它解决了你所面临的问题,并且
- 数据呈现给用户的方式通常与我希望它在数据库中的表示方式不同。这个映射可以让我很好地处理这个问题。
选项#2的缺点是重复复制数据。但是,您可以使用AutoMapper之类的工具来简化数据复制。