我有以下简单的结构: 申请人 Possition ApplicantPosition 和ApplicantPositionHistory
第3课有一个申请人参考,一个有职位。 第4个表有一个与ApplicantPosition
的引用在razon页面中,我正在显示申请人的每个职位的历史,我想以申请人的姓名显示
我在html中有这个,但它显示我为空,它只显示同一对象中的字段的信息,例如注释和日期修改。
@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 { private HRContext context = new 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]”的模型项。 / p>
答案 0 :(得分:2)
如何实现ApplicantPositionHistoryRepository的Find方法?如果它像
那样return entities.ApplicantPosition.SingleOrDefault(expression)
然后您必须启用急切加载,如下所示:
return entities.ApplicantPosition.Include("Applicant").SingleOrDefault(expression)
顺便说一下,这就是为什么我个人不喜欢这些“通用”存储库 - 有总是的情况,你需要急切加载某些东西,以及它只是浪费资源的情况。在“非通用”存储库中,您只需创建两个方法
GetApplicantPositionWithApplicant(int id)
GetApplicantPosition(int id)
以及你的表达式(如果你考虑它实际上是查询逻辑)保留在模型(存储库)而不是控制器中。
编辑(回答评论)
关于通用存储库的“痛苦”:只有在构建一些真正的BIG应用程序时,通用存储库才是一个好主意,您希望在更多层中分离内容,通常是 - 数据访问层(通用存储库),业务层(业务逻辑,工作流,高级验证等),然后是控制和表示层(控制器+ MVC中的视图)。在这种情况下,通用存储库仅封装普通的CRUD逻辑,仅由业务层使用,而不是由控制器使用。
如果您没有进行繁重的工作(非平凡的工作流程,验证需要外部服务等),那么您就不需要业务层,并且可以将其“合并”在数据访问层中(或如果你愿意,将数据访问合并到商业层,它们就会成为一体的灵魂:)
因此,如果您没有真正的业务层,那么您最终只能在控制器中使用某些业务逻辑,因为您的通用存储库并不是非常适合这种情况。非通用存储库可以包含您的简单业务处理,并且您还可以为不同的场景实现自定义CRUD - 非常好的示例是只有在您知道需要时才会急切加载事物。
所以重写的决定取决于你,取决于你的架构和需求。
关于您的例外:
使用SingleOrDefault,您的变量历史记录只包含一个ApplicationPositionHistory对象,您的视图需要枚举ApplicationPositionHistory对象。使用明确的返回值将此数据检索封装在存储库调用中,您将防止此类错误。
答案 1 :(得分:0)
您能否显示从数据库中获取项目列表的代码?
您是否尝试调试该代码?是否要在从数据库加载的页面上显示所有内容(因为默认情况下EF不加载关联实体)?