【问题标题】:asp.net mvc page is not showing properties from associated objectsasp.net mvc 页面未显示关联对象的属性
【发布时间】:2011-10-26 09:50:50
【问题描述】:

我有以下简单的结构: 申请人 职位 应聘职位 和申请人职位历史

第 3 类有一份关于申请人的参考资料和一份关于职位的参考资料。 第 4 表与申请人职位有一个参考

在我正在做的显示每个职位的申请人历史记录的 razon 页面中,我想显示申请人的姓名,例如

我在 html 中有这个,但它显示我是空的,它只显示同一对象中的字段的信息,例如 cmets 和 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);
        }

编辑 UnitofWork.cs

公共类 UnitOfWork { 私有 HRContext 上下文 = 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]”的模型项。

【问题讨论】:

    标签: asp.net-mvc entity-framework entity-framework-4.1


    【解决方案1】:

    您的ApplicantPositionHistoryRepository 的Find 方法是如何实现的?如果是这样的

    return entities.ApplicantPosition.SingleOrDefault(expression)
    

    那么您必须像这样启用即时加载

    return entities.ApplicantPosition.Include("Applicant").SingleOrDefault(expression)
    

    顺便说一句,这就是我个人不喜欢这些“通用”存储库的原因 - 存在总是需要急切加载某些内容的情况,以及只是浪费资源的情况。在“非通用”存储库中,您只需创建两个方法

    GetApplicantPositionWithApplicant(int id)

    GetApplicantPosition(int id)

    还有您的表达式(如果您考虑一下,实际上是查询逻辑)保留在模型(存储库)而不是控制器中。

    编辑(回答 cmets)

    关于通用存储库的“痛苦”:通用存储库通常是一个好主意,只有当您构建一些非常大的应用程序时,您希望在更多层中分离事物,通常是数据访问层(通用存储库),业务层(业务逻辑、工作流、高级验证等),然后是控制和表示层(MVC 中的控制器+视图)。在这种情况下,通用存储库只封装了琐碎的 CRUD 逻辑,并且仅供业务层使用,而不是控制器。

    如果您没有一些繁重的工作(重要的工作流程、需要外部服务的验证等),那么您就不需要业务层,您可以将其“合并”到数据访问层(或如果您愿意,可以将数据访问合并到业务层中,它们将成为一体的灵魂:)

    所以,如果你没有一些真正的业务层,你只能在控制器中得到一些业务逻辑,因为你的通用存储库不太适合。非通用存储库可以包含您的琐碎业务处理,您还可以为不同的场景实施自定义 CRUD - 非常好的示例是仅在您知道需要它们时才急切加载)。

    因此,重写的决定完全取决于您,并且取决于您的架构和需求。

    关于您的例外情况:

    使用 SingleOrDefault,您的变量历史记录仅包含一个 ApplicationPositionHistory 对象,并且您的视图需要枚举 ApplicationPositionHistory 对象。将此数据检索封装在存储库调用中,并带有明确的返回值,您将防止此类错误。

    【讨论】:

    • 它是这样实现的: public IQueryable Find(System.Linq.Expressions.Expression> predicate) { return dbSet.Where(predicate); }
    • 看起来我的整个通用存储库很痛苦,需要重写,或者是否有其他方法可以使其与通用存储库一起使用?
    • 你能检查一下我编辑的最后一部分吗,我试着按照你说的进行更改,但我遇到了这个例外。
    【解决方案2】:

    您能否显示从数据库中获取项目列表的代码?

    您是否尝试调试该代码?您想在页面上显示的所有内容是否都是从数据库加载的(因为 EF 默认不加载关联实体)?

    【讨论】:

    • 我刚刚编辑了问题并发布了控制器操作,那么如何使其加载上述代码中的关联实体?
    • 您能否也发布ApplicantPositionHistoryRepository 类的代码(这就是EF 代码所在的位置,对吧)?要进行 EF 负载关联,您必须在查询中调用 Include。 (但我不确定这是问题所在,所以请在您访问 ObjectContext 或 DbContext 的位置发布代码)
    • 我使用了存储库和工作单元模式,我只是粘贴了上下文、存储库和工作单元的整个代码。
    猜你喜欢
    • 1970-01-01
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多