T必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法中将其用作参数"TModel"

Adr*_* K. 11 c# generics asp.net-mvc abstract-class entity-framework

我已经尝试搜索SO以获得答案并偶然发现类似的问题,但我无法使用它们来解决我的问题,所以请尽量不要将其标记为重复.让我们继续谈谈真正的交易:

我有一个通用库,用于标准化实体框架数据库的第一个模型.这些是我创建的泛型类:

public abstract class GenericLookupModel : IActive, ICreated, IModified, IIdentity, IStringValue
{
    public bool is_active { get; set; }
    public string value { get; set; }
    public string description { get; set; }
    public DateTime created_on { get; set; }
    public string created_by { get; set; }
    public DateTime modified_on { get; set; }
    public string modified_by { get; set; }
    public int id {get;set;}

    public void SetCreated(string creator = "SYSTEM")
    {
        created_by = creator;
        created_on = DateTime.Now;
    }

    public void SetModified(string modifier = "SYSTEM")
    {
        modified_by = modifier;
        modified_on = DateTime.Now;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且ViewModel的类具有预先设置的MVC属性

public abstract class GenericLookupViewModel
{
    [Key]
    public int ID { get; set; }

    [Required]
    [StringLength(300)]
    public string Name { get; set; }

    [StringLength(4000)]
    public string Description { get; set; }

    [Required]
    public bool Active { get; set; }

    [StringLength(50)]
    [DisplayName("Record last modified by")]
    public string ModifiedBy { get; set; }

    [DisplayName("Record last modified Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime ModifiedOn { get; set; }

    [StringLength(50)]
    [DisplayName("Record created by")]
    public string CreatedBy { get; set; }

    [DisplayName("Record creation Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
    public DateTime CreatedOn { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

另外,我已经创建了一个服务类,我打算在控制器中使用它来获取数据:

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object 
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{
    private readonly DbContext _db;

    private DbContext entities
    {
        get { return _db; }
    }

    public GenericLookupModelDataService()
    {
        _db =
            new DbContext(
                System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ConnectionString);
    }

    public virtual IEnumerable<TViewModel> ReadAllActive()
    {
        return entities.Set<TModel>().Where(x => x.is_active).Select(product => new TViewModel
        {
            ID = product.id,
            Active = product.is_active,
            Description = product.description,
            Name = product.value,
            CreatedBy = product.created_by,
            CreatedOn = product.created_on,
            ModifiedBy = product.modified_by,
            ModifiedOn = product.modified_on
        });
    }

    public virtual IEnumerable<TViewModel> Read()
    {
        return entities.Set<TModel>().Select(product => new TViewModel
        {
            ID = product.id,
            Active = product.is_active,
            Description = product.description,
            Name = product.value,
            CreatedBy = product.created_by,
            CreatedOn = product.created_on,
            ModifiedBy = product.modified_by,
            ModifiedOn = product.modified_on
        });
    }

    public virtual void Create(TViewModel product, string username = "SYSTEM")
    {
        var entity = new TModel
        {
            is_active = product.Active,
            description = product.Description,
            value = product.Name,
        };

        entity.SetCreated();
        entity.SetModified();

        _db.Set<TModel>().Add(entity);
        _db.SaveChanges();
    }

    public virtual void Update(TViewModel product, string username = "SYSTEM")
    {
        var entity = new TModel
        {
            id = product.ID,
            is_active = product.Active,
            description = product.Description,
            value = product.Name
        };
        entity.SetModified();


        _db.Set<TModel>().Attach(entity);
        entities.Entry(entity).State = EntityState.Modified;
        entities.SaveChanges();
    }

    public virtual void Destroy(TViewModel product)
    {
        var entity = new TModel {id = product.ID};

        entities.Set<TModel>().Attach(entity);
        entities.Set<TModel>().Remove(entity);
        entities.SaveChanges();
    }

    public virtual TViewModel GetByID(int ID)
    {
        var item = entities.Set<TModel>().Find(ID);
        var result = new TViewModel
        {
            ID = item.id,
            Active = item.is_active,
            CreatedBy = item.created_by,
            CreatedOn = item.created_on,
            Description = item.description,
            ModifiedBy = item.modified_by,
            ModifiedOn = item.modified_on,
            Name = item.value
        };
        return result;
    }

    public void Dispose()
    {
        entities.Dispose();
    }

}
Run Code Online (Sandbox Code Playgroud)

库编译得很好,我在我的MVC App里面的数据层项目中使用它.首先创建一个新的视图模型:

public class RoleViewModel : GenericLookupViewModel
{


}
Run Code Online (Sandbox Code Playgroud)

然后,让我们创建一个服务:

public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{

}
Run Code Online (Sandbox Code Playgroud)

使Entity Framework类继承自抽象模型:

partial class tblkp_Role : GenericLookupModel
{

}
Run Code Online (Sandbox Code Playgroud)

最后让我们创建我们的控制器:

public class EmployeeController : Controller
{
    private RoleService roleService;

    public EmployeeController()
    {
        dataService = new EmployeeService();
        PopulateLookups();
    }

    private void PopulateLookups()
    {
        roleService = new RoleService();
        ViewData["roles"] = roleService.ReadAllActive();
    }

    public ActionResult Index()
    {
        return View();
    }

}
Run Code Online (Sandbox Code Playgroud)

对于代码墙感到抱歉,为简洁起见,已删除了一些代码.编译它时给了我3个错误: 在此输入图像描述

更新:提供由EF自动生成的tblk_Role类(DB First方法):

using System;
using System.Collections.Generic;

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

    public int id { get; set; }
    public string value { get; set; }
    public string desciption { get; set; }
    public bool is_active { get; set; }
    public System.DateTime created_on { get; set; }
    public string created_by { get; set; }
    public System.DateTime modified_on { get; set; }
    public string modified_by { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<tbl_Employee> tbl_Employee { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

更新2:纯文本格式的Erros:

错误33'DataLayer.Model.tblkp_Role'必须是具有公共无参数构造函数的非抽象类型,以便在泛型类型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'c中将其用作参数'TModel' :\项目\来源\ MyLib中\ BIN \发布\中是指mylib.dll

错误32类型'DataLayer.Model.tblkp_Role'不能用作泛型类型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'中的类型参数'TModel'.没有从'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的装箱转换.C:\项目\来源\ MyLib中\ BIN \发布\中是指mylib.dll

Jep*_*sen 24

你有以下几点:

public abstract class GenericLookupModelDataService<TModel, TViewModel> : object 
    where TModel : GenericLookupModel, new()
    where TViewModel : GenericLookupViewModel, new()
{
  // ...
Run Code Online (Sandbox Code Playgroud)

该类有两个名为TModel和的通用参数TViewModel.其中每个都有对它的约束,在wherecontextual关键字后面指出.

对于TModel约束是:

  • 一个基类约束,要求该类GenericLookupModel必须是所替换的类型的基类TModel,并且
  • 一个构造函数约束,new()要求用于的类型TModel必须公开一个public接受零参数的实例构造函数.

你问的一个错误是:

错误33"DataLayer.Model.tblkp_Role"必须是一个非抽象类型与公共参数构造,以便在通用类型或方法使用它作为参数"的TModel""MyLib.Model.GenericLookupModelDataService <TModel的,TViewModel>"

这只是意味着tblkp_Role您尝试使用的类型TModel不符合构造函数约束.你有0参数构造函数吗?

您询问的另一个错误是:

错误32类型'DataLayer.Model.tblkp_Role'不能用作泛型类型或方法'MyLib.Model.GenericLookupModelDataService <TModel,TViewModel>'中的类型参数'TModel'.没有从'DataLayer.Model.tblkp_Role'到'MyLib.Model.GenericLookupModel'的装箱转换.

这表示不满足基类约束.由于错误文本谈到"装箱转换",因此看起来tblkp_Role编译器正在使用的类型实际上是值类型(struct类型或enum类型).类似的类型永远不能从GenericLookupModel约束要求中派生出来.

它必须是tblkp_RoleC#编译器使用的类型,是与您定义的类型不同的另一种类型partial class tblkp_Role : GenericLookupModel.您可能在引用的项目中有一些冲突的名称或一些重复的代码/名称.

在编译时错误的映像版本中,我们看到编译器还抱怨tblkp_Role您使用的类型是在您没有引用的程序集中声明的.先尝试修复那个.一旦编译器可以看到所有细节,其他的将会消失,tblkp_Role因为它具有对定义该类型的项目的引用.