2

我是一名初学者程序员,在使用 @Html.DropDownListFor 助手时遇到了麻烦...

我正在使用基于此处教程的通用存储库和工作单元模式: http ://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository- and-unit-of-work-patterns-in-an-asp-net-mvc-application

这是我的存储库代码:

public class GenericRepository<TEntity> where TEntity : class
{
    internal UsersContext context;
    internal DbSet<TEntity> dbSet;

    public GenericRepository(UsersContext context)
    {
        this.context = context;
        this.dbSet = context.Set<TEntity>();
    }

    public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

    public virtual TEntity GetByID(object id)
    {
        return dbSet.Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        dbSet.Add(entity);
    }

    // Delete methods not shown

    public virtual void Update(TEntity entityToUpdate)
    {
        dbSet.Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

这是我的 UnitOfWork 类的代码:

public class UnitOfWork : IDisposable
{
    private UsersContext context = new UsersContext();
    private GenericRepository<UserProfile> userProfileRepository;
    private GenericRepository<Lead> leadRepository;
    private GenericRepository<UnitedStatesState> unitedStatesStateRepository;

    public GenericRepository<UserProfile> UserProfileRepository
    {
        get
        {

            if (this.userProfileRepository == null) 
            {
                this.userProfileRepository = new GenericRepository<UserProfile(context);
            }
            return userProfileRepository;
        }
    }

    public GenericRepository<Lead> LeadRepository
    {
        get
        {

            if (this.leadRepository == null)
            {
                this.leadRepository = new GenericRepository<Lead>(context);
            }
            return leadRepository;
        }
    }

    public GenericRepository<UnitedStatesState> UnitedStatesStateRepository 
    {
        get
        {

            if (this.unitedStatesStateRepository == null)
            {
                this.unitedStatesStateRepository = new GenericRepository<UnitedStatesState>(context);
            }
            return unitedStatesStateRepository;
        }
    } 

我正在尝试使用强类型视图和模型,以便在不使用 ViewData/ViewBag 的情况下将选择列表数据传递给视图。据我了解,最好的做法是做一些类似于我在这里看到的事情: validate a dropdownlist in asp.net mvc

我尝试尽可能地遵循这一点,这就是我想出的

我的视图模型如下所示:

public class Lead
{
    public int LeadID { get; set; }
    public int CompanyID { get; set; }

    [Required(ErrorMessage = "Please enter state")]
    [Display(Name = "State")]
    [MaxLength(2)]
    public string State { get; set; }

    [Display(Name = "Assigned To")]
    public string AssignedTo { get; set; }

    [Timestamp]
    public Byte[] Timestamp { get; set; }

    public virtual Company Company { get; set; }

    // IEnumerables for Dropdown Lists passed to views
    public IEnumerable<UnitedStatesState> UnitedStatesStates { get; set; }
    public IEnumerable<UserProfile> UserProfiles { get; set; }

    // Objects passed to views
    public Lead lead { get; set; }
}

然后,我的下拉列表的这些 IEnumerables 从我的数据库通过我的存储库填充到我的控制器中。奇怪的是,我在两个不同的视图中使用这些下拉列表,创建和编辑。当我在 Create 视图中使用下拉列表时,它们在 GET 和 POST ActionResults 上都能完美运行。当我尝试为我的编辑视图使用相同的下拉列表时,它们适用于 GET ActionResult(视图加载和下拉列表工作)但是当我尝试将它们发布到我的编辑 ActionResult 时,我收到以下错误:

{"Value cannot be null.\r\nParameter name: items"} // 这是 Visual Studio 2012 中显示的错误

System.ArgumentNullException:值不能为空。参数名称:items //这是谷歌浏览器中显示的错误

下面是我的主控制器,带有编辑和创建操作结果:

public class LeadController : Controller
{
    // create instance of Repository Unit of Work
    private UnitOfWork unitOfWork = new UnitOfWork();

    public ActionResult Create()
    {
        // Get the current users profile
        UserProfile userProfile = UserProfile.GetCurrentUserProfile();

        // Creates Dropdown Lists to pass to view
        var model = new Lead
        {
            UnitedStatesStates = unitOfWork.UnitedStatesStateRepository.Get(u => u.StateAbbreviation != null),
            UserProfiles = unitOfWork.UserProfileRepository.Get(u => u.CompanyID == userProfile.CompanyID)
        };

        // Return View
        return View(model);
    }

    [HttpPost]
    public ActionResult Create(Lead model)
    {
        try
        {
            if (ModelState.IsValid)
            {
                // Call the current users profile
                UserProfile userProfile = UserProfile.GetCurrentUserProfile(); 

                // Create a new lead and apply all attirbutes that were entered
                Lead lead = new Lead();
                lead.CompanyID = userProfile.CompanyID; 
                lead.State = model.State;
                lead.AssignedTo = model.AssignedTo;

                // Add the lead and save the changes.  Redirect to Lead Index.
                unitOfWork.LeadRepository.Insert(lead); 
                unitOfWork.Save(); 
                return RedirectToAction("Index");
            }
        }
        catch (DataException)
        {
            ModelState.AddModelError("", "Unable to save changes.  Try again and if the problem persists, see your system administrator.");
        }
        // Return view if ModelState is not valid
        return View();
    }

    public ActionResult Edit(int id = 0)
    {
        // Get Users Profile
        UserProfile userProfile = UserProfile.GetCurrentUserProfile();

        // Check to see if Lead Exists
        if (unitOfWork.LeadRepository.GetByID(id) == null)
        {
            return HttpNotFound();
        }

        // Creates Dropdown Lists and Gets current lead values to pass to view
        var model = new Lead
        {
            lead = unitOfWork.LeadRepository.GetByID(id),
            UnitedStatesStates = unitOfWork.UnitedStatesStateRepository.Get(u => u.StateAbbreviation != null),
            UserProfiles = unitOfWork.UserProfileRepository.Get(u => u.CompanyID == userProfile.CompanyID)
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Edit(Lead lead)
    {
        try
        {
            // Update lead if model state is valid
            if (ModelState.IsValid)
            {
                unitOfWork.LeadRepository.Update(lead);
                unitOfWork.Save();
                return RedirectToAction("Index");
            }
        }
        // Catch any concurrency exceptions
        catch (DbUpdateConcurrencyException ex)
        {
            var entry = ex.Entries.Single();
            var databaseValues = (Lead)entry.GetDatabaseValues().ToObject();
            var clientValues = (Lead)entry.Entity;

            if (databaseValues.State != clientValues.State)
                ModelState.AddModelError("State", "Current value: "
                    + databaseValues.State);

            if (databaseValues.AssignedTo != clientValues.AssignedTo )
                ModelState.AddModelError("Assigned To ", "Current value: "
                    + databaseValues.AssignedTo );

            ModelState.AddModelError(string.Empty, "The record you attempted to edit "
                + "was modified by another user after you got the original value. The "
                + "edit operation was canceled and the current values in the database "
                + "have been displayed. If you still want to edit this record, click "
                + "the Save button again. Otherwise click the Back to List hyperlink.");
            lead.Timestamp = databaseValues.Timestamp;
        }
        catch (DataException)
        {
            //Log the error (add a variable name after Exception)
            ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
        }

        // Return View if Model State is not valid
        return View(lead);
    }

POST Edit ActionResult 包括用于捕获我按照此处显示的教程创建的并发代码: http ://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with- asp-net-mvc 应用程序中的实体框架

以下是我对 Create 的看法(效果很好):

@model SolarToolbase.Models.Lead

@using (Html.BeginForm()) {                
@Html.ValidationSummary(true)
<div>                
    <div>
        @Html.LabelFor(model => model.State)
        @Html.DropDownListFor(model => model.State, new SelectList(Model.UnitedStatesStates, "StateAbbreviation", "UnitedStatesStateName"),"Choose State")<br />
        @Html.ValidationMessageFor(model => model.State)
    </div> 
    <div>
        @Html.LabelFor(model => model.AssignedTo)
        @Html.DropDownListFor(model => model.AssignedTo, new SelectList(Model.UserProfiles, "FullName", "FullName"),"Choose User")<br />
        @Html.ValidationMessageFor(model => model.AssignedTo)
    </div> 
    <p>
        <input type="submit" value="Create" />
    </p>

</div>
}   

下面是我对编辑的看法(当我点击提交按钮时,这会引发上述错误。我在下面插入了一条评论以显示引发错误的行):

@model SolarToolbase.Models.Lead

@using (Html.BeginForm()) {               
@Html.ValidationSummary(true) 
@Html.HiddenFor(model => model.lead.LeadID)
@Html.HiddenFor(model => model.lead.Timestamp)

<div>
    <div>
        @Html.LabelFor(model => model.lead.State)
        @Html.DropDownListFor(model => model.lead.State, new SelectList(Model.UnitedStatesStates, "StateAbbreviation", "UnitedStatesStateName"))<br />  // Error thrown from this line
        @Html.ValidationMessageFor(model => model.lead.State)
    </div> 
    <div>
        @Html.LabelFor(model => model.lead.AssignedTo)
        @Html.DropDownListFor(model => model.lead.AssignedTo, new SelectList(Model.UserProfiles, "FullName", "FullName"))<br />
        @Html.ValidationMessageFor(model => model.lead.AssignedTo)
    </div> 
    <p>
        <input type="submit" value="Save" />
    </p>   
</div> 
}

我提前为发布这么多代码而道歉,老实说,我不知道这个错误来自哪里,我已经把头撞在墙上试图弄清楚大约 4 个小时。任何可以提供帮助的人都可以免费虚拟击掌和良好的因果报应。

谢谢!

4

1 回答 1

0

在 aPOSTCreateEdit操作的情况下,当出现错误或ModelState无效时,您会捕获任何异常并返回由模型绑定器创建和填充View的构造视图模型的默认值。Lead

但是,在该Edit POST操作中,如果存在错误条件,则将lead对象返回给ViewModel.请注意,不会在 上重新填充UnitedStatesStatesUserProfiles属性POST。您在动作中填充它们GET,但您也必须在POST动作中这样做。您需要注意发送到视图的任何模型都处于正确的形状,并且填充了所有预期的成员。

另请注意,您的视图模型的类型Lead具有名为lead. 那是那里的代码气味;我不会有一个视图模型类引用它自己的类的实例。它已经让你感到困惑了。我必须LeadLeadViewModel明确的,只是让它在进出视图时保持它需要的所有属性和值,没有lead属性。

在您的Edit视图中,您引用的是模型的属性model.lead.State,例如,但在Create视图中,您引用的是父级属性,如model.State. 但是在Edit视图中,当涉及到SelectListItems您使用Model.UnitedStatesStates的而不是Model.lead.UnitedStatesStates.正如我所说的那样时,我会取消这种模式并做Create视图现在所做的事情,根本没有子lead属性。model.State例如,对所有属性和两个视图都这样做。

因此,请确保在将模型传递给视图时填充您的集合属性,如

[HttpPost]
public ActionResult Edit(Lead lead)
{
    try
    {
        // Update lead if model state is valid
        if (ModelState.IsValid)
        {
            unitOfWork.LeadRepository.Update(lead);
            unitOfWork.Save();
            return RedirectToAction("Index");
        }
    }
    // Catch any concurrency exceptions
    catch (DbUpdateConcurrencyException ex)
    {
        var entry = ex.Entries.Single();
        var databaseValues = (Lead)entry.GetDatabaseValues().ToObject();
        var clientValues = (Lead)entry.Entity;

        if (databaseValues.State != clientValues.State)
            ModelState.AddModelError("State", "Current value: "
                + databaseValues.State);

        if (databaseValues.AssignedTo != clientValues.AssignedTo )
            ModelState.AddModelError("Assigned To ", "Current value: "
                + databaseValues.AssignedTo );

        ModelState.AddModelError(string.Empty, "The record you attempted to edit "
            + "was modified by another user after you got the original value. The "
            + "edit operation was canceled and the current values in the database "
            + "have been displayed. If you still want to edit this record, click "
            + "the Save button again. Otherwise click the Back to List hyperlink.");
        lead.Timestamp = databaseValues.Timestamp;
    }
    catch (DataException)
    {
        //Log the error (add a variable name after Exception)
        ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
    }

    // Return View if Model State is not valid
    /////////// CHANGES HERE
    lead.UnitedStatesStates = unitOfWork.UnitedStatesStateRepository.Get(u => u.StateAbbreviation != null),
    lead.UserProfiles = unitOfWork.UserProfileRepository.Get(u => u.CompanyID == userProfile.CompanyID)
    return View(lead); // pass the model to the view for Create and Edit POST actions when there's an error
}

在这两个POST动作中都这样做。如果出现错误,视图将由具有填充模型的操作实例化。还要将视图更改为EditCreate视图一样工作,而不是使用Lead视图模型的lead属性。大概这将处理视图中的任何空引用异常。

于 2013-05-16T21:48:00.810 回答