带有 UserId 的 MVC Core SelectList 并加入另一个 table

MVC Core SelectList with UserId and Join to another table

我搜索了大量答案并尝试了多种编码方法。目前我得到

System.Data.Entity.Core.EntityCommandExecutionException: 'The data reader has more than one field. Multiple fields are not valid for EDM primitive or enumeration types.'

我的部分观点。

我想学这个,所以我花了最后 40 个小时研究和尝试不同的方法。我终于大声呼救了。

我只是想要一个包含所有这些的下拉框:

[Key] UserId  - all user Id's taken from Identity Model
value = Users.LastName + ', ' + Users.FirstName + ' - Council: ' + CAST(Groups.CouncilNumber AS VARCHAR) + ', ' + UnitTypes.Name + ' ' + CAST(Groups.UnitNumber AS VARCHAR)

所以我可以为客户记录分配一个 UserId。需要显示 以便用户有足够的信息 select 正确的 UserId。

Linqer 给了我这个来代替我的 SQL。即使在用 ApplicationUser 替换 db.AspnetUsers 之后,我似乎也无法让它工作。

var query = 
        from Users in db.AspNetUsers
        join Groups in db.Groups on new { GroupId = Convert.ToInt32(Users.GroupId) } equals new { GroupId = Groups.GroupId }
        join UnitTypes in db.UnitTypes on Groups.UnitTypeId equals UnitTypes.UnitTypeId
        orderby
          Users.LastName,
          Users.FirstName
        select new {
          Users.Id,
          FullDescription = (Users.LastName + ", " + Users.FirstName + " - Council: " + Convert.ToString(Groups.CouncilNumber) + ", " + UnitTypes.Name + " " + Convert.ToString(Groups.UnitNumber))
        };
    foreach (var r in query)
        Add(new AspNetUser(
            r.Id, r.FullDescription))

这是我的设置:

public class CustomerViewModel : DbContext{ 
        public CustomerViewModel(): base("name=CustomerViewModel"){ }

        [Key]
        public int CustomerId { get; set; }

        [Required(ErrorMessage = "Please enter your first name.")]
        [StringLength(50)]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "Please enter your last name.")]
        [StringLength(100)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }        

        [MaxLength(128), ForeignKey("ApplicationUser")]
        public string UserId { get; set; }
        public SelectList UserSelectList { get; set; }

        public virtual ApplicationUser ApplicationUser { get; set; }
    }
}

namespace WOA.Models {
    public class ApplicationUser : IdentityUser {
        [Required(ErrorMessage = "Please enter your first name.")]
        [StringLength(50)]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "Please enter your last name.")]
        [StringLength(100)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        public int? GroupId { get; set; }

        public int CustomerId { get; set; }

        [ForeignKey("GroupId")]
        public virtual Group Group { get; set; }
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }
}

namespace WOA.Models {
    public class Group {
        public int GroupId { get; set; }
        public int CouncilNumber { get; set; }
        public int UnitTypeId { get; set; }
        public string UnitNumber { get; set; }
        [ForeignKey("UnitTypeId")]
        public virtual UnitType UnitType { get; set; }
    }
}

namespace WOA.Models{
    public class UnitType{
        public int UnitTypeId { get; set; }
        [Required] public string Name { get; set; }
    }
}

namespace WOA.Controllers {
    public class CustomersController : Controller {
        private CustomerViewModel MapToViewModel(Models.Customer customer) {
            CustomerViewModel customerVm = new CustomerViewModel() {
                CustomerId = customer.CustomerId,
                GroupId = customer.GroupId
            };

            return customerVm;
        }       

        public ActionResult Edit(int customerId){

            CustomerViewModel customerViewModel = MapToViewModel(customer);
            customerViewModel.UserSelectList = GetUserGroupList(DbContext); 

            if (Request.IsAjaxRequest())
            {
                return PartialView("_CustomerEditPartial", customerViewModel);
            }

            return PartialView("_CustomerEditPartial", customerViewModel); 
        }

        public SelectList GetUserGroupList(DbContext _dbContext) {
            var sql = @"SELECT Users.Id as Value
                    , Users.LastName + ', ' + Users.FirstName + ' - Council: ' + CAST(Groups.CouncilNumber AS VARCHAR) + ', ' + UnitTypes.Name + ' ' + CAST(Groups.UnitNumber AS VARCHAR) AS Text
                FROM dbo.AspNetUsers AS Users
                    JOIN dbo.Groups ON Users.GroupId = dbo.Groups.GroupId
                JOIN dbo.UnitTypes ON dbo.Groups.UnitTypeId = dbo.UnitTypes.UnitTypeId
                Order by Users.LastName, Users.FirstName ";


            var kk = _dbContext.Database.SqlQuery<string>(sql);

            SelectList mySl = new SelectList(kk, "Value", "Text");
            return mySl;
        }
    }
}


@model WOA.ViewModels.CustomerViewModel

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

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

        <div class="form-group">
            @Html.LabelFor(model => model.UserId, "UserId", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.UserId, ViewData.Model.UserSelectList, "Select One", new { @class = "form-control" })

                @*@Html.DropDownListFor(model => model.UserId, new SelectList(Model.UserSelectList, "Value", "Text"), htmlAttributes: new { @class = "form-control", id = "UserId" })*@
                @Html.ValidationMessageFor(model => model.UserId, "", new { @class = "text-danger" })
            </div>
        </div>

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

        <div class="form-group">
            @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.LastName, "", 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>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

异常消息很明显:来自 EF return 的 SQL 数据 reader(SqlQuery 方法)超过单个值(即 Users.Id 和来自多列的连接字符串)。

此查询 returns Value & Text 结果集中的列别名,而 SqlQuery 的 return 类型应该是单个 string:

var sql = @"SELECT Users.Id as Value, 
            Users.LastName + ', ' + Users.FirstName + ' - Council: ' + CAST(Groups.CouncilNumber AS VARCHAR) + ', ' + UnitTypes.Name + ' ' + CAST(Groups.UnitNumber AS VARCHAR) AS Text
            FROM dbo.AspNetUsers AS Users
            JOIN dbo.Groups ON Users.GroupId = dbo.Groups.GroupId
            JOIN dbo.UnitTypes ON dbo.Groups.UnitTypeId = dbo.UnitTypes.UnitTypeId
            Order by Users.LastName, Users.FirstName ";

要解决此问题,请尝试创建额外的 class,其中包含 2 个对应于文本和值属性的属性,例如 SelectListItem 具有:

public class QueryResults
{
    public string Value { get; set; } // change to int if Users.Id has integer value
    public string Text { get; set; }
}

然后,将查询结果绑定到指定的视图模型中,然后创建List<SelectListItem>

var kk = _dbContext.Database.SqlQuery<QueryResults>(sql).ToList();

SelectList mySl = new SelectList(kk, "Value", "Text");

可以找到类似的问题