0

我有以下实体模型:

public class AssetLabel
{
    public string QRCode { get; set; }
    public string asset { get; set; }
    public virtual IEnumerable<Conversation> Conversations { get; set; }
}

public class Conversation
{
    public int ID { get; set; }
    public virtual AssetLabel AssetLabel{ get; set; }
    public string FinderName { get; set; }
    public string FinderMobile { get; set; } 
    public string FinderEmail  { get; set; }
    public  ConversationStatus Status{ get; set; }

    public IEnumerable<ConversationMessage> Messages { get; set; }
}

public class ConversationMessage
{
    public int ID { get; set; }
    public DateTime MessageDateTime { get; set; }
    public bool IsFinderMessage { get; set; }
    public virtual Conversation Conversation { get; set; }
}

public enum ConversationStatus { open, closed };

public class FinderViewModel : Conversation
{/*used in Controllers->Found*/


}

我的 MVC 应用程序将提示QRCode一个 POST 请求。然后我验证此代码是否存在于数据库中AssetLabel,并且满足其他一些服务器端逻辑。然后我需要请求用户联系方式来创建新 Conversation记录。目前我有一个 GET 到一个控制器操作,它返回第一个表单来捕获代码。如果这是有效的,那么我创建一个新 的,用对象FinderViewModel填充并返回一个视图以使用 vm 并显示,和的字段。我的问题是,虽然作为 的一部分被传递给视图,但我可以显示来自;的字段。图形对象不会在 POST 中传回。我知道我可以修改AssetLabelQRCodeNameMobileEmailAssetLabelFinderViewModelAssetLabelAssetLabelFinderViewModel因此它将Conversationas 一个属性设置QRCode为一个单独的属性,该属性可能是表单中的隐藏字段,然后重新找到 theAssetLabel作为第二个表单处理的一部分,但这感觉像是很多工作因为我已经验证过一次以达到创建第二种形式的目的(这就是我离开 PHP MVC 框架的原因)。

第一个问题是如何?,第二个问题是我是否以错误的方式接近这种设计模式。是否有更 .NETty 的方式通过多种形式保存数据?在我学习的这一点上,我真的不想将信息存储在 cookie 中或使用 ajax。

作为参考,第 1 形式 POST、第 2 视图和第 2 形式 POST 的其余代码如下所示(已简化以消除不相关的逻辑)。

public class FoundController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    // GET: Found
    public ActionResult Index()
    {
        AssetLabel lbl = new AssetLabel();
        return View(lbl);
    }

    [HttpPost]
    public ActionResult Index(string QRCode)
    {
        if (QRCode=="")
        {
            return Content("no value entered");
        }
        else
        {
            /*check to see if code is in database*/
            AssetLabel lbl = db.AssetLables.FirstOrDefault(q =>q.QRCode==QRCode);
            if (lbl != null)
            {
                var vm = new FinderViewModel();
                vm.AssetLabel = lbl;
                vm.Status = ConversationStatus.open;

                return View("FinderDetails", vm);
            }
            else
            {/*Label ID is not in the database*/
                return Content("Label Not Found");
            }
        }
    }

    [HttpPost]
    public ActionResult ProcessFinder(FinderViewModel vm)
    {
        /*
        THIS IS WHERE I AM STUCK! - vm.AssetLabel == NULL even though it
        was passed to the view with a fully populated object
        */
        return Content(vm.AssetLabel.QRCode.ToString());
        //return Content("Finder Details posted!");
    }

FinderView.cshtml

@model GMSB.ViewModels.FinderViewModel

@{
     ViewBag.Title = "TEST FINDER";
}

<h2>FinderDetails</h2>

@using (Html.BeginForm("ProcessFinder","Found",FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
    <h4>Finder Details</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.ID)
    @Html.HiddenFor(model => model.AssetLabel)

    <div class="form-group">
        @Html.LabelFor(model => model.FinderName, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderName, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderName, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.FinderMobile, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderMobile, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderMobile, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.FinderEmail, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.FinderEmail, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.FinderEmail, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</div>

}

AssetLabel 的渲染 HTML 片段

<input id="AssetLabel" name="AssetLabel" type="hidden"       
value="System.Data.Entity.DynamicProxies.AssetLabel_32653C4084FF0CBCFDBE520EA1FC5FE4F22B6D9CD6D5A87E7F1B7A198A59DBB3" 
/>
4

2 回答 2

2
于 2016-11-12T21:59:51.077 回答
0

谢谢斯蒂芬。QRCode 是 AssetLabel 上的 PK 和 Conversation 中的 FK,因此需要通过工作流程对其进行跟踪。我试图保持 viewModel 通用,以便可用于其他表单,而不是将其紧密耦合到此特定表单,并且我试图传递 AssetLabel,因为我已经对其状态进行了大量验证,我不想重复。我想出了我需要做什么 - 如果您使用 @Html.Hidden(model => model.AssetLabel.QRCode) 那么表单字段名称将变为 AssetLabel_QRCode 并自动映射到 POST 视图模型中的正确位置。为了促进代码重用并避免以后的任何返工,我在显示模板中创建了这个逻辑,其中字段定义为隐藏,然后是 @Html。

@Html.Partial
(
    "./Templates/Assetlabel_hidden", 
    (GMSB.Models.AssetLabel)(Model.AssetLabel), 
    new ViewDataDictionary()
    {
        TemplateInfo = new TemplateInfo()
        {
            HtmlFieldPrefix = "AssetLabel"
        }
    }
)

但你是绝对正确的,这会暴露额外的字段和我的应用程序结构。我想我将重新起草 viewModel 以仅公开必要的字段并将 AssetLabel 验证移动到一个单独的私有函数,该函数可以从初始 POST 和后续帖子中调用。这确实意味着控制器中有额外的代码,因为平面 vm 字段需要手动映射到复杂的对象图。

于 2016-11-12T22:36:20.747 回答