【问题标题】:Cannot implicitly convert type 'System.Collections.Generic.List<MODEL#1>' to 'System.Collections.Generic.List<Model#2>无法将类型 'System.Collections.Generic.List<MODEL#1>' 隐式转换为 'System.Collections.Generic.List<Model#2>
【发布时间】:2016-06-27 00:10:34
【问题描述】:

我正在使用带有 EF6 的 MVC5。我收到以下转换错误

不能隐式转换类型 System.Collections.Generic.List&lt;TreaceabilitySystem.GLB_M_PROFITCENTER&gt;System.Collections.Generic.List&lt;TreaceabilitySystem.Models.Profitcenter&gt;

        private TSEntities db = new TSEntities();
        // GET: Profitcenter
        public ActionResult Index()
        {

            List<Profitcenter> profitcenter = new List<Profitcenter>();
            profitcenter = db.GLB_M_PROFITCENTER.ToList(); //Error coming up here
            return View(profitcenter.ToList());
        }

我的模型在这里: 当我在 .edmx 中添加表格时,这个模型是通过 EF 创建的

 public partial class GLB_M_PROFITCENTER
        {
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
            public GLB_M_PROFITCENTER()
            {
                this.GLB_M_USERMASTER = new HashSet<GLB_M_USERMASTER>();
            }

            public string PROFITCENTER_CODE { get; set; }
            public string PROFITCENTER_NAME { get; set; }
            public string DESCRIPTION { get; set; }
            public bool ISACTIVE { get; set; }
            public int CREATEDBY { get; set; }
            public System.DateTime CREATED_DATE { get; set; }
            public Nullable<int> UPDATEDBY { get; set; }
            public Nullable<System.DateTime> UPDATED_DATETIME { get; set; }

            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
            public virtual ICollection<GLB_M_USERMASTER> GLB_M_USERMASTER { get; set; }
        }

我创建了以下模型用于更改显示名称和验证目的

 [MetadataType(typeof(Profitcenter))]
    public partial class GLB_M_PROFITCENTER { }

     public class Profitcenter
        {
            [Required(ErrorMessage = "*")]
            [DisplayName("Profitcenter Code")]
            public string PROFITCENTER_CODE { get; set; }
            [Required(ErrorMessage = "*")]
            [DisplayName("Profitcenter Name")]
            public string PROFITCENTER_NAME { get; set; }


            [DisplayName("Description")]
            public string DESCRIPTION { get; set; }

            [DisplayName("Is Active")]
            public bool ISACTIVE { get; set; }

            [DisplayName("Created By")]
            public int CREATEDBY { get; set; }

            [DisplayName("Created Timestamp")]
            public System.DateTime CREATED_DATE { get; set; }

            [DisplayName("Upated by")]
            public Nullable<int> UPDATEDBY { get; set; }

            [DisplayName("Updated Timestamp")]
            public DateTime UPDATED_DATETIME
            {
                get; set;
            }
        }

两个型号完全一样,我有什么遗漏吗? 我该如何解决这个问题?

【问题讨论】:

  • 两个型号怎么一模一样?它们对我来说看起来不同......一个是部分类,另一个是带有嵌套类的部分类。此外,命名空间不同 - TreaceabilitySystem.GLB_M_PROFITCENTERTreaceabilitySystem.Models.Profitcenter。即使这些类是相同的(它们不是),编译器也会将它们视为不同的类。
  • 这两个属性只是相同的,对吧?我只使用属性
  • 命名空间使它们不同。 TraceabilitySystem.GLB_M_PROFITCENTER.PROFITCENTER_CODETraceabilitySystem.Models.ProfitCenter.PROFITCENTER_CODE 不同。
  • 但是这个错误与此有关吗?我该如何解决?
  • 此外,属性相同。如果它们相同,您就不必复制该类。它们是故意不同的。区别在于它们的属性。

标签: c# asp.net-mvc entity-framework


【解决方案1】:

两个模型完全相同

这并不意味着您可以将一个分配给另一个。要使此代码正常工作:

Foo foo = new Foo();
Bar bar = foo;

Bar 必须是Foo 的基本类型。这不是这里的情况,您的BarFoo 恰好具有相同的属性名称。

你需要从一个映射到另一个:

public Profitcenter Map(GLB_M_PROFITCENTER input)
{
    return new Profitcenter
    {
        PROFITCENTER_CODE = input.PROFITCENTER_CODE,
        ...
    };
}

你可以用Select()做整个列表的映射:

List<Profitcenter> profitcenter = new List<Profitcenter>();
profitcenter = db.GLB_M_PROFITCENTER.Select(Map).ToList();

一种自动执行此操作的方法是使用 AutoMapper,如果双方的所有属性都命名相同,它会特别有效。

不过,这只能部分回答您的问题。您有两种类型:GLB_M_PROFITCENTER,一个 Entity Framework 生成的表示数据库表的类,以及Profitcenter,您在其中添加了可用于使用 MetadataType 属性进行输入验证的属性。

我不喜欢后者,因为您使用实体框架模型作为 UI 层的视图模型。您不应该这样做,您可以从部分类定义中删除 MetadataType 属性。

因此,您可以使用 MetadataType,但永远不要真正实例化该类型(毕竟,它是一个 元数据 类型):

List<GLB_M_PROFITCENTER> profitcenter = db.GLB_M_PROFITCENTER.ToList();
return View(profitcenter);

让你的观点@model IEnumerable&lt;GLB_M_PROFITCENTER&gt;。然后 MVC 将读取 GLB_M_PROFITCENTERMetadataType 属性,并将元数据(DisplayName,...)应用到 Profitcenter(但你不应该)。

或者您可以简单地应用映射,从而将您的视图模型与您的实体模型(以及您的数据库)解耦,并获得所有额外的好处。

【讨论】:

  • 绝对是的。同样,如果您的课程有 50 个属性并且您没有使用像 AutoMapper 这样的扩展,那么这很痛苦 :)。但是,是的,就是这样。
  • 如何将属性应用于自动生成的模型?
  • @King_Fisher 我不知道你的意思是什么以及它与我的答案有何关系。
  • 如果我在视图中使用自动生成的模型(GLB_M_PROFITCENTER),我想更改显示名称和所有内容。如何添加这些属性?
  • @King_Fisher 我将不得不将您推荐给我的earlier comment
【解决方案2】:

某些编程语言,不像 C# 和其他类似 C 的语言允许使用所谓的 "duck typing",如果它们都“以相同的方式”,您可以从不同的类型进行分配。

但是,在 C# 中,您只能将类的实例分配给相同类型或基类型(您的类扩展的类或它实现的接口)的变量。即使您有两个看起来完全相同的类,您也无法将其中一个分配给另一个。 .NET 4.0 之前的版本甚至不支持适当的通用 covariance and contravariance,这意味着即使 Tderived 派生自 Tbase,您甚至无法将 IEnumerable&lt;Tderived&gt; 分配给 IEnumerable&lt;Tbase&gt;

解决办法是:

  1. 使用将映射从一个类到另一个类的工具(即在同名属性之间复制),如AutoMapper,或

  2. 重新设计您的应用程序以拥有一个单独的程序集,其中包含要在其他程序集类型之间共享的公共实体(也不是一个坏主意),或者

  3. 提取一个接口,以便您可以分配给此基本接口。

使用映射来解决这个问题并不少见,因为您经常希望使用普通的data transfer objects 在层之间移动数据,因此使用自动化工具是可以的,但如果您可以将所有实体保存在一个DAL 和业务层都引用了单独的程序集,但对它们一无所知,那么这是一种更好的方法,因为它避免了任何运行时映射问题。

【讨论】:

    【解决方案3】:

    GLB_M_PROFITCENTER 和 Profitcenter 不是同一类型,您只是共享元数据,以便从视图模型到实体模型共享属性。您应该使用 linq 投影将一种类型转换为另一种类型

    db.GLB_M_PROFITCENTER.select(e => new Profitcenter() {
         /* props mapping*/
    }).ToList()
    

    您也可以使用映射引擎,例如AutoMapper

    【讨论】:

      【解决方案4】:

      如果成员名称相同 - 使用自动映射器 - 它会自动转换每种类型。

      Mapper.CreateMap<SourceType, DestinationType>()
      

      然后就可以调用了

      Mapper.Map<DestinationType>(instanceofSourceType);
      

      【讨论】:

      • 这更像是一个评论而不是一个答案。
      • 考虑将其作为评论而不是答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      相关资源
      最近更新 更多