2016-01-20 10 views
10

Ho provato a cercare SO per la risposta e sono incappato in problemi simili, ma non ho potuto t riesco a usarli per risolvere il mio problema, quindi prova a non contrassegnarlo come duplicato. Passiamo al vero affare:T deve essere un tipo non astratto con un costruttore pubblico senza parametri per utilizzarlo come parametro "TModel" nel tipo o metodo generico

Ho una libreria generica per standardizzare i primi modelli di database del framework di entità. Queste sono le classi generiche che ho creato:

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; 
    } 
} 

e una classe per il ViewModel con pre-impostare MVC attributi

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; } 
} 

Inoltre, ho creato una classe di servizio che intendo di utilizzare all'interno del controller per ottenere i dati:

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(); 
    } 

} 

la biblioteca compila bene, lo uso all'interno del progetto strato di dati dentro la mia MVC App. Iniziate creando una nuova vista del modello:

public class RoleViewModel : GenericLookupViewModel 
{ 


} 

Quindi, consente di creare un servizio:

public class RoleService : GenericLookupModelDataService<tblkp_Role, RoleViewModel> 
{ 

} 

rendere la classe eredita Entity Framework dal modello astratto:

partial class tblkp_Role : GenericLookupModel 
{ 

} 

lasciare infine di crea il nostro controller:

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(); 
    } 

} 

Ci scusiamo per il wall-of-code, alcuni codici sono già stati rimossi per brevità. Durante la compilazione mi dà 3 errori: enter image description here

UPDATE: disponibile Class tblk_Role generato automaticamente da EF (DB Primo approccio):

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; } 
} 

UPDATE 2: Erros in formato testo:

Errore 33 'DataLayer.Model.tblkp_Role' deve essere un tipo non astratta con un pubblico costruttore senza parametri al fine di utilizzarlo come parametro 'tModel' nel tipo generico o di un metodo 'MyLib.Model.GenericLookupModelDataService < tModel, TViewModel >' C: \ Progetti \ Sources \ MyLib \ bin \ Release \ MyLib.dll

Errore 32 il tipo 'DataLayer.Model.tblkp_Role' non può essere utilizzato come parametro di tipo 'tModel' nel tipo generico o metodo 'MyLib.Model.GenericLookupModelDataService < tModel, TViewModel >'. Lì non è la conversione di boxe da "DataLayer.Model.tblkp_Role" a "MyLib.Model.GenericLookupModel". c: \ Progetti \ Sources \ MyLib \ bin \ Release \ MyLib.dll

+0

Uno dei tuoi errori dice che devi aggiungere un riferimento. L'hai fatto? – Maarten

+1

Per spiegarlo: Nel controller si utilizza il 'RoleService', che eredita direttamente da' GenericLookupModelDataService '. Una conseguenza di questo disegno è che qualsiasi altra classe che utilizza il 'RoleService' (ad esempio il tuo' EmployeeController') deve anche avere una conoscenza diretta di tutto ciò che è direttamente esposto nell'albero ereditario. Pertanto, anche 'tblkp_Role' deve essere conosciuto dal controller. – Maarten

+0

Sì, l'ho fatto. Il riferimento bibliografico esiste in tutti e 3 i progetti nella mia soluzione. Sembra che il controller non abbia problemi a conoscere tblkp_Role –

risposta

16

Sono disponibili le seguenti:

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

Questa classe ha due paramters generico chiamato TModel e TViewModel. Ognuno di questi ha vincoli, indicato dopo la parola chiave contestuale where.

Per TModel i vincoli sono:

  • un vincolo classe base richiedendo che la classe GenericLookupModel deve essere una classe base di ciò che mai tipo viene sostituito a TModel e
  • un vincolo costruttore new() richiedendo che il tipo utilizzato per TModel deve esporre un costruttore di istanze public che accetta zero argomenti.

Uno degli errori che si chiede circa è:

Errore 33 'DataLayer.Model.tblkp_Role' deve essere un tipo non astratta con un costruttore senza parametri pubblico al fine di utilizzarlo come parametro 'tModel' nel tipo generico o metodo 'MyLib.Model.GenericLookupModelDataService < tModel, TViewModel >'

Ciò significa semplicemente che il tipo 0.123.che si tenta di utilizzare per TModel non è conforme al vincolo del costruttore. Hai il costruttore di parametri 0?

Un altro errore di chiedere informazioni è:

Errore 32 Il tipo 'DataLayer.Model.tblkp_Role' non può essere utilizzato come tipo di parametro 'tModel' nel tipo generico o di un metodo 'MyLib.Model. GenericLookupModelDataService < TModel, TViewModel > '. Lì non è la conversione di boxe da "DataLayer.Model.tblkp_Role" a "MyLib.Model.GenericLookupModel".

Ciò indica che il vincolo della classe base non è soddisfatto. Poiché il testo dell'errore parla di "conversione di boxe", sembra che il tipo tblkp_Role utilizzato dal compilatore sia in realtà un tipo di valore (tipo struct o tipo enum). Tipi come quello non possono mai derivare da GenericLookupModel come richiede il vincolo.

Deve essere che il tipo tblkp_Role utilizzato dal compilatore C#, è un altro tipo rispetto al tipo definito con partial class tblkp_Role : GenericLookupModel. Potresti avere alcuni nomi in conflitto o alcuni codici/nomi duplicati dai progetti di riferimento.

Nella versione di immagine degli errori in fase di compilazione, vediamo che il compilatore si lamenta anche che il tipo tblkp_Role che si utilizza sia dichiarato in un assembly a cui non si ha alcun riferimento. Prova a risolverlo per primo. Forse gli altri andranno via una volta che il compilatore può vedere tutti i dettagli di tblkp_Role perché ha il riferimento al progetto che definisce quel tipo.

2

L'errore che hai citato di solito si presenta quando cerchi di utilizzare lo stesso parametro di tipo generico in classi diverse senza definire tutti i vincoli in almeno uno di essi. Vedi this La risposta di Jon Skeet per chiarezza.

Ma si utilizza tModel in una sola classe qui vale a dire GenericLookupModelDataService, quindi ho provato la seguente:

Ho scritto tutto il codice nello stesso file di codice che significa nessuna libreria esterna. Qualcosa di simile:

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() 
    { 

    } 
} 

Questo compila correttamente. Quindi sospetto che il compilatore non sia a conoscenza della definizione completa di tblkp_Role.

Suggerirei di ri costruire la libreria e rinominarla di nuovo (Controllare anche il percorso di riferimento per assicurarsi di non riferirsi erroneamente alla versione precedente).

Ho affrontato problemi simili con le classi parziali che vengono create automaticamente da EF nel primo approccio DB in particolare quando ho provato a definire le classi di metadati.

Problemi correlati