简体   繁体   English

MVC和实体框架中的嵌套查找

[英]Nested lookup in MVC and Entity Framework

I'm running into a problem with a project I'm working on. 我正在研究的项目遇到问题。 I'm relatively new to MVC so I'm hoping this is something simple! 我是MVC的新手,所以希望这很简单!

I'm trying to perform an edit on an object, but the object in question has a couple of ICollections that it can't seem to bind to. 我正在尝试对一个对象执行编辑,但是有问题的对象具有似乎无法绑定到的几个ICollections。

The class I'm trying to update is called 'Key', and the definition is: 我尝试更新的类称为“键”,其定义为:

public partial class Key
{
    public Key()
    {
        this.KeyFields = new HashSet<KeyField>();
        this.KeyServices = new HashSet<KeyService>();
    }

    public int ID { get; set; }
    public System.Guid APIKey { get; set; }
    public string SiteURL { get; set; }
    public bool Active { get; set; }
    public virtual ICollection<KeyField> KeyFields { get; set; }
    public virtual ICollection<KeyService> KeyServices { get; set; }
}

The KeyField and KeyService classes are: KeyField和KeyService类为:

public partial class KeyField
{
    public int ID { get; set; }
    public int SiteKey { get; set; }
    public int Field { get; set; }
    public bool Active { get; set; }

    public virtual Field Field1 { get; set; }
    public virtual Key Key { get; set; }
}

public partial class KeyService
{
    public int ID { get; set; }
    public int SiteKey { get; set; }
    public int Service { get; set; }
    public bool Active { get; set; }

    public virtual Key Key { get; set; }
    public virtual Service Service1 { get; set; }
}

The related Service class is: 相关的Service类是:

public partial class Service
{
    public Service()
    {
        this.KeyServices = new HashSet<KeyService>();
    }

    public int ID { get; set; }
    public string Name { get; set; }
    public int Service_View { get; set; }

    public virtual ICollection<KeyService> KeyServices { get; set; }
    public virtual View View { get; set; }

    [NotMapped]
    public bool IsSelected { get; set; }
}

and the related Field class is: 和相关的Field类是:

public partial class Field
{
    public Field()
    {
        this.KeyFields = new HashSet<KeyField>();
    }

    public int ID { get; set; }
    public string Title { get; set; }
    public int Field_View { get; set; }

    public virtual View View { get; set; }
    public virtual ICollection<KeyField> KeyFields { get; set; }

    [NotMapped]
    public bool IsSelected { get; set; }
}

The View is using a custom model called 'KeyDetailsModel'. 视图使用名为“ KeyDetailsModel”的自定义模型。 It contains an instance of the 'Key' object and 2 IEnumerables. 它包含一个“键”对象的实例和2个IEnumerables。 These are there so that I can output all the fields and services in the database into a list of checkboxes on the View. 这些是在那里,因此我可以将数据库中的所有字段和服务输出到视图上的复选框列表中。 The fields and services that should be preselected on the View are ICollections in the Key class. 在View上应该预先选择的字段和服务是Key类中的ICollections。 the definition is: 定义是:

public class KeyDetailsModel
{
    public Key Key { get; set; }
    public IEnumerable<Field> Fields { get; set; } 
    public IEnumerable<Service> Services { get; set; } 
}

The is the code in the controller that sets up the 'display' page: 这是设置“显示”页面的控制器中的代码:

    public ViewResult KeyDetails(int id)
    {
        var fieldChannel = new Repo<Field>();
        var serviceChannel = new Repo<Service>();

        //gets the key information
        var key = _keyChannel.GetById(id);

        //gets all the fields in the database
        var fields = fieldChannel.GetAll();

        //gets all the services in the database
        var services = serviceChannel.GetAll();

        //gets the KeyFields for the key, and sets the IsSelected flag for the related Field
        foreach (var f in fields)
        {
            var selectedField = (from sf in key.KeyFields
                                 where sf.ID == f.ID && sf.SiteKey == id
                                 select sf).FirstOrDefault();

            if (selectedField != null)
            {
                f.IsSelected = true;
            }
        }

        //gets the KeyServices for the key, and sets the IsSelected flag for the related Service
        foreach (var f in services)
        {
            var selectedService = (from ss in key.KeyServices
                                 where ss.ID == f.ID && ss.SiteKey == id
                                 select ss).FirstOrDefault();

            if (selectedService != null)
            {
                f.IsSelected = true;
            }
        }

        //create the model
        var KeyDetailsModel = new KeyDetailsModel
        {
            Fields = fields,
            Key = key,
            Services = services
        };

        return View(KeyDetailsModel);
    }

This is the method in the controller that will perform the edit: 这是控制器中将执行编辑的方法:

    [HttpPost]
    public ActionResult KeyDetails(KeyDetailsModel KeyDetailsModel)
    {
        if (KeyDetailsModel != null && ModelState.IsValid)
        {
            return View(KeyDetailsModel);
        }
        else
        {
            return View(KeyDetailsModel);
        }
    }

Finally, the cshtml page is: 最后,cshtml页面是:

@model EdinburghNapier.EAWebLayer.Admin.Models.KeyDetailsModel

@{
   ViewBag.Title = "KeyDetails";
   Layout = "~/Views/Shared/_Layout.cshtml";
 }

<h2>Key Details</h2>

@using (Html.BeginForm("KeyDetails", "Key", FormMethod.Post))
{
<fieldset>
    <legend>Key</legend>

    <div class="display-label">
        @Html.DisplayNameFor(model => model.Key.APIKey)
    </div>
    <div class="display-field">
        @Html.EditorFor(model => model.Key.APIKey)
    </div>

    <div class="display-label">
        @Html.DisplayNameFor(model => model.Key.SiteURL)
    </div>
    <div class="display-field">
        @Html.EditorFor(model => model.Key.SiteURL)
    </div>

    <div class="display-label">
        @Html.DisplayNameFor(model => model.Key.Active)
    </div>
    <div class="display-field">
        @Html.EditorFor(model => model.Key.Active)
    </div>


    <div class="display-field">
        <ul>
            @foreach (var f in Model.Fields)
            {
                <li>
                    <input type="checkbox"
                           name="Key.KeyFields" value="@f.ID" id="Field_@f.ID"
                           checked="@f.IsSelected"/>
                    <label for="@f.ID">@f.Title</label>
                </li>
            }
        </ul>
    </div>

    <div class="display-field">
        <ul>
            @foreach (var f in Model.Services)
            {
                <li>
                    <input type="checkbox"
                   name="Key.KeyServices" value="@f.ID" id="Service_@f.ID"
                   checked="@f.IsSelected"/>
                    <label for="@f.ID">@f.Name</label>
                </li>
            }
        </ul>
    </div>
</fieldset>    
@Html.HiddenFor(model => model.Key.ID)
<input type="submit" value="Save"/>
}

What is happening when I submit the form is that the 'KeyFields' and 'KeyServices' properties of the 'Key' class in the 'KeyDetailsModel' are always 0. The edit screen doesn not seem to be able to bind the check box lists to the properties. 提交表单时发生的情况是,“ KeyDetailsModel”中“ Key”类的“ KeyFields”和“ KeyServices”属性始终为0。编辑屏幕似乎无法将复选框列表绑定到属性。 One consequence of this is that the status of the ModelState is always false when I submit. 其结果之一是,在我提交时,ModelState的状态始终为false。

I've been bashing my head against a wall over this for a couple of days now, hope someone can help! 我已经在这上面砸了头几天,希望有人能帮忙! I appreciate that I may have supplied too much code and too little explanation - please let me know if that's the case! 我很感谢我提供的代码过多,解释也很少-如果是这种情况,请告诉我!

You are binding your checkboxes in incorrect way, you should read a bit more about it, you can check some article like this: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ 您以错误的方式绑定了复选框,您应该阅读更多有关该复选框的信息,您可以查看如下文章: http : //haacked.com/archive/2008/10/23/model-binding-to-a- list.aspx /

Your code should be changed, so that each checkbox had an indexer in its name: 您的代码应进行更改,以便每个复选框的名称中都有一个索引器:

<div class="display-field">
    <ul>
        @for (var i = 0; i < Model.Fields.Count(); i++)
             {
            <li>
                <input type="checkbox"
                       name="@Html.NameFor(x=>x.Fields[i])" value="@Model.Fields[i].ID" id="@Html.IdFor(x=>x.Fields[i])"
                       checked="@Model.Fields[i].IsSelected" />
                <label for="@Html.NameFor(x=>x.Fields[i])">@Model.Fields[i].Title</label>
            </li>
        }
    </ul>
</div>

<div class="display-field">
    <ul>
        @for (var i = 0; i < Model.Services.Count(); i++)
                {
                <li>
                    <input type="checkbox"
                           name="@Html.NameFor(x=>x.Services[i])" value="@Model.Services[i].ID" id="@Html.IdFor(x=>x.Services[i])"
                           checked="@Model.Services[i].IsSelected" />
                    <label for="@Html.NameFor(x=>x.Services[i])">@Model.Services[i].Name</label>
                </li>
        }
    </ul>
</div>

You will also have to make your Services and Fields properties an array here: 您还必须在此处将“服务和字段”属性设置为数组:

public class KeyDetailsModel
{
    public Key Key { get; set; }
    public Field[] Fields { get; set; } 
    public Service[] Services { get; set; } 
}

Alternately, you can just use @Html.CheckBoxFor(x=>x.Fields[i].IsSelected inside the cycle, stick to Mvc Helpers, they really make the difference. 或者,您可以只使用@Html.CheckBoxFor(x=>x.Fields[i].IsSelected ,在循环内,坚持使用Mvc Helpers,它们确实会有所作为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM