在不同命名空间的基类上使用属性和元数据

本文关键字:属性 元数据 基类 命名空间 | 更新日期: 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>。当您在视图中使用强类型模型时,它必须与操作返回的模型匹配。

这个错误有两种可能的解决方案:

  1. 更改视图以使用IEnumerable<Name1.Person>作为其模型,或
  2. 改变你的动作,返回一个IEnumerable<NameMvc.Person>作为模型。

当您使用MetadataType向您的模型添加元数据时,最常见的方法是使用原始模型类作为部分类生成的事实。您为分部类创建另一个"部分",并向其添加MetadataType属性。

但是,分部类不能跨程序集使用。因此,这意味着如果您将模型移动到它自己的程序集中,那么您就不能将部分类添加到MVC项目中以添加元数据。

要解决这个问题,可以执行以下操作之一:

  1. 在模型的程序集中添加元数据。为此,您可以在模型的程序集中使用部分类解决方案。这样做的问题是,你现在混合了视图逻辑和数据逻辑。
  2. 在MVC项目中创建一个新类,它是数据模型的伪副本,用作视图模型。将元数据添加到其中。你的动作会返回这个视图模型你的视图会使用它。在您的操作中,您将数据从数据模型复制到视图模型。

我更喜欢选项#2,原因如下:

  1. 它解决了你所面临的问题,并且
  2. 数据呈现给用户的方式通常与我希望它在数据库中的表示方式不同。这个映射可以让我很好地处理这个问题。

选项#2的缺点是重复复制数据。但是,您可以使用AutoMapper之类的工具来简化数据复制。