У меня следующая простая структура:
заявитель
Possition
ApplicantPosition
и ApplicantPositionHistory
3-й класс имеет одну ссылку с заявителем и одну с позицией.
В 4-й таблице есть одна ссылка с ApplicantPosition
На странице razon, которую я делаю, чтобы показать историю кандидата на должность, я хочу показать имя кандидата, например,
У меня есть это в html, однако оно показывает меня пустым, оно показывает мне информацию только для полей, которые находятся в одном и том же объекте, например комментарии и datemodified.
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.applicantPosition.Applicant.name)
</td>
<td>
@Html.DisplayFor(modelItem => item.applicantPosition.Position.name)
</td>
<td>
@Html.DisplayFor(modelItem => item.oldStatus.status)
</td>
<td>
@Html.DisplayFor(modelItem => item.newStatus.status)
</td>
<td>
@Html.DisplayFor(modelItem => item.comments)
</td>
<td>
@Html.DisplayFor(modelItem => item.dateModified)
</td>
Моя модель такая:
namespace Data.Model
{
public class Position
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int PositionID { get; set; }
[Required(ErrorMessage = "Position name is required.")]
[StringLength(20, MinimumLength = 3, ErrorMessage = "Name should not be longer than 20 characters.")]
[Display(Name = "Position name")]
public string name { get; set; }
[Required(ErrorMessage = "Number of years is required")]
[Display(Name = "Number of years")]
[YearsValidationAttribute(5, ErrorMessage = "{0} value must be greater than {1} years.")]
public int yearsExperienceRequired { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
}
public class Applicant
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int ApplicantID { get; set; }
[Required(ErrorMessage = "Name is required")]
[StringLength(20, MinimumLength = 3, ErrorMessage="Name should not be longer than 20 characters.")]
[Display(Name = "First and LastName")]
public string name { get; set; }
[Required(ErrorMessage = "Telephone number is required")]
[StringLength(20, MinimumLength = 3, ErrorMessage = "Telephone should not be longer than 20 characters.")]
[Display(Name = "Telephone Number")]
public string telephone { get; set; }
[Required(ErrorMessage = "Skype username is required")]
[StringLength(20, MinimumLength = 3, ErrorMessage = "Skype user should not be longer than 20 characters.")]
[Display(Name = "Skype Username")]
public string skypeuser { get; set; }
public byte[] photo { get; set; }
public virtual ICollection<ApplicantPosition> applicantPosition { get; set; }
}
public class ApplicantPosition
{
[Key]
[Column("ApplicantID", Order = 0)]
public int ApplicantID { get; set; }
[Key]
[Column("PositionID", Order = 1)]
public int PositionID { get; set; }
public virtual Position Position { get; set; }
public virtual Applicant Applicant { get; set; }
[Required(ErrorMessage = "Applied date is required")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Display(Name = "Date applied")]
public DateTime appliedDate { get; set; }
[Column("StatusID", Order = 0)]
public int StatusID { get; set; }
public Status Status { get; set; }
//[NotMapped]
//public int numberOfApplicantsApplied
//{
// get
// {
// int query =
// (from ap in Position
// where ap.Status == (int)Status.Applied
// select ap
// ).Count();
// return query;
// }
//}
}
public class Address
{
[StringLength(20, MinimumLength = 3, ErrorMessage = "Country should not be longer than 20 characters.")]
public string Country { get; set; }
[StringLength(20, MinimumLength = 3, ErrorMessage = "City should not be longer than 20 characters.")]
public string City { get; set; }
[StringLength(50, MinimumLength = 3, ErrorMessage = "Address should not be longer than 50 characters.")]
[Display(Name = "Address Line 1")]
public string AddressLine1 { get; set; }
[Display(Name = "Address Line 2")]
public string AddressLine2 { get; set; }
}
public class ApplicationPositionHistory
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int ApplicationPositionHistoryID { get; set; }
public ApplicantPosition applicantPosition { get; set; }
[Column("oldStatusID")]
public int oldStatusID { get; set; }
[Column("newStatusID")]
public int newStatusID { get; set; }
[ForeignKey("oldStatusID")]
public Status oldStatus { get; set; }
[ForeignKey("newStatusID")]
public Status newStatus { get; set; }
[StringLength(500, MinimumLength = 3, ErrorMessage = "Comments should not be longer than 500 characters.")]
[Display(Name = "Comments")]
public string comments { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Display(Name = "Date")]
public DateTime dateModified { get; set; }
}
public class Status
{
[DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
public int StatusID { get; set; }
[StringLength(40, MinimumLength = 3, ErrorMessage = "Status should not be longer than 20 characters.")]
[Display(Name = "Status")]
public string status { get; set; }
}
}
Действие контроллера
public ViewResult History(int applicantId, int positionId)
{
var history= unitOfWork.ApplicantPositionHistoryRepository.Find(d => d.applicantPosition.ApplicantID == applicantId && d.applicantPosition.PositionID == positionId);
return View(history);
}
EDIT
UnitofWork.cs
открытый класс UnitOfWork
{
закрытый контекст HRContext = новый HRContext ();
private BaseRepository<Position> positiontRepository;
private BaseRepository<ApplicantPosition> applicantpositiontRepository;
private BaseRepository<Applicant> applicantRepository;
private BaseRepository<Status> statusRepository;
private BaseRepository<ApplicationPositionHistory> applicantPositionHistoryRepository;
public BaseRepository<ApplicationPositionHistory> ApplicantPositionHistoryRepository
{
get
{
if (this.applicantPositionHistoryRepository == null)
{
this.applicantPositionHistoryRepository = new BaseRepository<ApplicationPositionHistory>(context);
}
return applicantPositionHistoryRepository;
}
}
public BaseRepository<Status> StatusRepository
{
get
{
if (this.statusRepository == null)
{
this.statusRepository = new BaseRepository<Status>(context);
}
return statusRepository;
}
}
public BaseRepository<Applicant> ApplicantRepository
{
get
{
if (this.applicantRepository == null)
{
this.applicantRepository = new BaseRepository<Applicant>(context);
}
return applicantRepository;
}
}
public BaseRepository<Position> PositionRepository
{
get
{
if (this.positiontRepository == null)
{
this.positiontRepository = new BaseRepository<Position>(context);
}
return positiontRepository;
}
}
public BaseRepository<ApplicantPosition> ApplicantPositionRepository
{
get
{
if (this.applicantpositiontRepository == null)
{
this.applicantpositiontRepository = new BaseRepository<ApplicantPosition>(context);
}
return applicantpositiontRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
HRContext.cs
public class HRContext : DbContext
{
public DbSet<Position> Positions { get; set; }
public DbSet<Applicant> Applicants { get; set; }
public DbSet<ApplicantPosition> ApplicantsPositions { get; set; }
public DbSet<ApplicationPositionHistory> ApplicationsPositionHistory { get; set; }
public DbSet<Status> Status { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Position>().ToTable("Position");
modelBuilder.Entity<Applicant>().ToTable("Applicant");
modelBuilder.Entity<ApplicantPosition>().ToTable("ApplicantPosition");
modelBuilder.Entity<ApplicationPositionHistory>().ToTable("ApplicationsPositionHistory");
modelBuilder.Entity<Status>().ToTable("Status");
modelBuilder.Entity<Position>().Property(c => c.name).IsRequired();
modelBuilder.Entity<Applicant>().Property(c => c.name).IsRequired();
modelBuilder.Entity<ApplicantPosition>().Property(c => c.appliedDate).IsRequired();
modelBuilder.Entity<ApplicationPositionHistory>().Property(c => c.ApplicationPositionHistoryID).IsRequired();
modelBuilder.Entity<Status>().Property(c => c.StatusID).IsRequired();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
base.OnModelCreating(modelBuilder);
}
}
BaseRepository.cs
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal HRContext context;
internal DbSet<TEntity> dbSet;
public BaseRepository(HRContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void DeleteAll(List<TEntity> entities)
{
foreach (var entity in entities)
{
this.Delete(entity);
}
}
public virtual List<TEntity> GetAll()
{
return context.Set<TEntity>().ToList();
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
public IQueryable<TEntity> Find(System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate)
{
return dbSet.Where(predicate);
}
}
IRepository.cs
public interface IRepository<TEntity>
{
IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
void Insert(TEntity entity);
void Delete(TEntity entity);
void DeleteAll(List<TEntity> entities);
}
Я изменил общий репозиторий и изменил метод действия контроллера следующим образом:
public ViewResult History(int applicantId, int positionId)
{
//var history= unitOfWork.ApplicantPositionHistoryRepository.Find(d => d.applicantPosition.ApplicantID == applicantId && d.applicantPosition.PositionID == positionId);
var history= db.ApplicationsPositionHistory.Include("ApplicantPosition").SingleOrDefault(d => d.applicantPosition.ApplicantID == applicantId && d.applicantPosition.PositionID == positionId);
return View(history);
}
Однако я получаю это исключение:
Элемент модели, передаваемый в словарь, имеет тип «Data.Model.ApplicationPositionHistory», но для этого словаря требуется элемент модели типа «System.Collections.Generic.IEnumerable`1 [Data.Model.ApplicationPositionHistory]».