T должен быть не абстрактным типом с открытым конструктором без параметров, чтобы использовать его в качестве параметра "TModel" в общем типе или методе
Я попытался найти ответ и наткнулся на подобные проблемы, но мне не удалось использовать их для решения моей проблемы, поэтому, пожалуйста, постарайтесь не отмечать это как дубликат. Давайте перейдем к реальной сделке:
у меня есть общая библиотека для стандартизации первых моделей базы данных entity framework. Это универсальные классы, которые я создал:
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;
}
}
и класс для 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; }
}
кроме того, у меня создал класс обслуживания, который я намерен использовать внутри контроллера для получения данных:
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();
}
}
библиотека компилируется отлично, я использую его внутри проекта слоя данных внутри моего приложения MVC. Начните с создания новой модели вида:
public class RoleViewModel : GenericLookupViewModel
{
}
тогда, давайте создадим сервис:
public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel>
{
}
сделайте класс Entity Framework наследуемым от абстрактной модели:
partial class tblkp_Role : GenericLookupModel
{
}
наконец, давайте создадим наш контроллер:
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();
}
}
извините за стены-кода, какой код уже был удален для краткости. При компиляции он дает мне 3 ошибки:
обновление: при условии, что класс tblk_Role генерируется автоматически EF (DB первый подход):
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; }
}
обновление 2: Erros в текстовом формате:
Ошибка 33 ' DataLayer.Модель.tblkp_Role должен быть неабстрактный тип с открытым конструктором без параметров, чтобы использовать его как параметр "TModel" в универсальном типе или методе 'Библиотеки MyLib.Модель.GenericLookupModelDataService' c:ProjectsSourcesMyLibbinReleaseMyLib - ... dll файлы
ошибка 32 тип ' DataLayer.Модель.tblkp_Role ' нельзя использовать в качестве типа параметр "TModel" в универсальном типе или методе 'Библиотеки MyLib.Модель.GenericLookupModelDataService'. Там нет преобразования бокса из ' DataLayer.Модель.tblkp_Role в 'Библиотеки MyLib.Модель.GenericLookupModel'. c:ProjectsSourcesMyLibbinReleaseMyLib.dll файлы
2 ответов
у вас есть следующие:
public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
where TModel : GenericLookupModel, new()
where TViewModel : GenericLookupViewModel, new()
{
// ...
этот класс имеет два общих параметра, называемых TModel
и TViewModel
. У каждого из них есть ограничения к нему, указанному после where
контекстное ключевое слово.
на TModel
ограничения:
- ограничение базового класса, требующее, чтобы класс
GenericLookupModel
должен быть базовый класс того, что когда-либо тип заменяется наTModel
и - a ограничение конструктора
new()
требуется, чтобы тип, используемый дляTModel
должен предоставлятьpublic
конструктор экземпляра, который принимает нулевые аргументы.
одна из ошибок, о которой вы спрашиваете:
Ошибка 33 ' DataLayer.Модель.tblkp_Role должен быть неабстрактный тип с открытым конструктором без параметров, чтобы использовать его как параметр "TModel" в универсальном типе или методе 'Библиотеки MyLib.Модель.GenericLookupModelDataService
'
это просто означает, что тип tblkp_Role
что вы пытаетесь использовать для TModel
не соответствует ограничению конструктора. У вас есть конструктор 0-parameter?
еще одна ошибка, о которой вы спрашиваете:
ошибка 32 тип ' DataLayer.Модель.tblkp_Role' не может быть использован в качестве параметр типа "TModel" в универсальном типе или методе 'Библиотеки MyLib.Модель.GenericLookupModelDataService
'. Там нет преобразования бокса из ' DataLayer.Модель.tblkp_Role в 'Библиотеки MyLib.Модель.GenericLookupModel'.
это означает, что ограничение базового класса не встречал. Поскольку текст ошибки говорит о "конверсии бокса", кажется, что тип tblkp_Role
который использует компилятор, на самом деле является типом значения (struct
тип, или enum
тип). Такие типы никогда не могут быть производными от GenericLookupModel
как ограничение требует.
должно быть, что тип tblkp_Role
, который использует компилятор C#, является другим типом, чем тип, который вы определяете с partial class tblkp_Role : GenericLookupModel
. У вас могут быть некоторые конфликтующие имена или некоторые дубликаты кода/имен из ссылочных проектов.
в версии образа ваших ошибок времени компиляции мы видим, что компилятор также жалуется, что тип tblkp_Role
который вы используете, объявляется в сборке, на которую у вас нет ссылки. Попробуй сначала это исправить. Может быть, другой они исчезнут, как только компилятор сможет увидеть все детали tblkp_Role
потому что он имеет ссылку на проект, который определяет, что тип.
ошибка, о которой Вы упомянули, обычно возникает при попытке использовать один и тот же параметр универсального типа в разных классах без определения всех ограничений хотя бы в одном из них. См.этой ответ Джона Скита для ясности.
но вы используете TModel только в одном классе здесь, т. е. GenericLookupModelDataService, поэтому я попробовал следующее:
Я написал весь ваш код в одном файле кода, что означает отсутствие внешней библиотеки. Что-то вроде этого:
class Program
{
static void Main(string[] args)
{
RoleService roleService = new RoleService();
}
}
class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel>
{ }
public abstract class GenericLookupModelDataService<TModel, TViewModel> : object
where TModel : GenericLookupModel, new()
where TViewModel : GenericLookupViewModel, new()
{ }
public abstract class GenericLookupViewModel { }
public abstract class GenericLookupModel { }
public class RoleViewModel : GenericLookupViewModel { }
public partial class tblkp_Role : GenericLookupModel
{
}
public partial class tblkp_Role
{
public tblkp_Role()
{
}
}
это успешно компилируется. Поэтому я подозреваю, что компилятор не знает полного определения tblkp_Role.
Я бы предложил повторно создать библиотеку и повторно ссылаться на нее снова (также проверьте путь ссылки, чтобы убедиться, что вы не ошибочно ссылаетесь на более старую версию).
я столкнулся с аналогичными проблемами с частичными классами, которые автоматически создаются EF в DB first approach, особенно когда я пытался определить метаданные занятия.