Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 671|回复: 0

关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】

[复制链接]
  • TA的每日心情
    奋斗
    7 天前
  • 签到天数: 745 天

    [LV.9]以坛为家II

    2041

    主题

    2099

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    704660
    发表于 2021-7-22 17:03:44 | 显示全部楼层 |阅读模式

    最近一直用ASP.NET MVC 4.0 +LINQ TO SQL来开发设计公司内部多个业务系统网站,在这其中发现了一些问题,也花了不少时间来查找相关资料或请教高人,最终都还算解决了,现在我将这些问题及对应的解决方案都整理汇总出来,供大家参供,有不对之处或有更好的解决办法,欢迎在本文评论,谢谢!

    【2014-12-2发布】

    问题一:执行类似语句:dbDataContext.TableName.Join(modelList as List<实体对象类型>,t1=>t1.id,t2=>t2.id,(t1,t2)=>new{属性赋值}),报错:不能在查询运算符(Contains 运算符除外)的 LINQ to SQL 实现中使用本地序列。

    原因分析:数据表映射实体对象无法与C#自有集合对象关联查询,必需确保LINQ 语句进行查询与运算均为数据表映射实体对象或C#自有集合对象

    解决方案:dbDataContext.TableName.Join(dbDataContext.TableName2,t1=>t1.id,t2=>t2.id,(t1,t2)=>new{属性赋值}),或dbDataContext.TableName.AsEnumerable().Join(modelList as List<实体对象类型>,t1=>t1.id,t2=>t2.id,(t1,t2)=>new{属性赋值}),但后者存在性能问题,因为AsEnumerable()就会立即执行查询动作,将TableName中所有的数据加载到本地内存中后才去与后面的modelList 关联。

     

    问题二:执行类似语句:dbDataContext.TableName.Select(t=>new 数据表映射实体类{属性赋值}),报错:不允许在查询中显式构造实体类型“XXXXXXXXX”。

    原因分析:摘自网络上的原话“LINQ to SQL在RTM之前的版本有个Bug,如果在查询中显式构造一个实体的话,在某些情况下会得到一系列完全相同的对象。很可惜这个Bug我只在资料中看到过,而在RTM版本的LINQ to SQL中这个Bug已经被修补了,确切地说是绕过了。直接抛出异常不失为一种“解决问题”的办法,虽然这实际上是去除了一个功能——没有功能自然不会有Bug,就像没有头就不会头痛了一个道理。”

    解决方案:1.将Select(t=>new 数据表映射实体类{属性赋值})改为直接返回匿名类:Select(t=>new {属性赋值}),或重新定义该实体类对象,去掉与数据表映射相关的特性,即:Select(t=>new 自定义实体类{属性赋值}),2.利用LINQ to SQL中DataContext提供有GetCommand方法,扩展方法ExecuteQuery<T>,代码如下:

    public static class DataContextExtensions
    {
        public static List<T> ExecuteQuery<T>(this DataContext dataContext, IQueryable query)
        {
            DbCommand command = dataContext.GetCommand(query);
            dataContext.OpenConnection();
     
            using (DbDataReader reader = command.ExecuteReader())
            {
                return dataContext.Translate<T>(reader).ToList();
            }
        }
     
        private static void OpenConnection(this DataContext dataContext)
        {
            if (dataContext.Connection.State == ConnectionState.Closed)
            {
                dataContext.Connection.Open();
            }
        }
    }

    在执行的时候就可以先以LINQ查询,然后执行ExecuteQuery方法,如:

    var query=dbDataContext.TableName.Select();
    var modelList=dbDataContext.ExecuteQuery<数据表映射实体类>(query);

    问题三:使用ModelState.AddModelError(“字段名”,“错误信息”)添加多个信息时,在VIEW中用Html.ValidationSummary(false) 显示的报错顺序不一定与AddModelError的先后顺序相同,即:

    ModelState.AddModelError(“字段名1”,“错误信息1”);
    ModelState.AddModelError(“字段名9”,“错误信息2”);
    ModelState.AddModelError(“字段名6”,“错误信息3”);
    ModelState.AddModelError(“字段名3”,“错误信息4”);
    ModelState.AddModelError(“字段名5”,“错误信息5”);

    显示出来可能是(无序的或以字段名排序后显示):

    错误信息1
    错误信息4
    错误信息5
    错误信息3
    错误信息9

    这就明显会影响用户体验,所以建议使用以下方法,这样显示出来的错误就是正常的,原理很简单,因为若ModelState.AddModelError为同一个键,此处为空,则会在该键的ModelState.Errors下添加项,而由于Errors最终存为List类型,所以索引顺序也就确定了

    ModelState.AddModelError(“”,“错误信息1”);
    ModelState.AddModelError(“”,“错误信息2”);
    ModelState.AddModelError(“”,“错误信息3”);
    ModelState.AddModelError(“”,“错误信息4”);
    ModelState.AddModelError(“”,“错误信息5”);

     

    问题四:将匿名对象作为Model数据传给View并显示时,报错:“object”不包含“XXX”的定义。

    原因分析:匿名类型默认访问修饰符为internal,这意味着他们只可以从其定义的程序集中被访问。一旦你超越了程序集的边界,将会被当做普通的object对象被解析,因此不具备直接索引属性。

    解决方案:1.使用Tuple元组静态类,即:

    Controller中:
    var
    result= dbDataContext.TableName.Select(s=>Tuple.Create(参数赋值)); View中使用: @model IEnumerable<dynamic> foreach (var item in Model) { <tr> <td>@item.Item1</td> <td>@item.Item2</td> <td>@item.Item3</td> <td>@item.Item4</td> <td>@item.Item5</td> </tr> }

    2.还可以使用ExpandoObject类,这是.NET 4.0中的一种类型:ExpandoObject,ExpandoObject类型是一种可以再运行时随意动态添加和删除成员的类型。

     
     
    Controller中:
    public ActionResult UsingExpando()  
    {  
        dynamic viewModel = new ExpandoObject();  
        viewModel.TestString = "This is a test string";  
       
        return View(viewModel);  
    }  
    
    View中使用:
    
    <p> @Model.TestString </p>

     

    【2014-12-09发布】

    问题五:从视图页面接收到MODEL对象后(POST到ACTION),对MODEL对象各属性进行变更并重新传给视图显示,但显示的结果仍然是之前视图上编辑的MODEL的值

            public ActionResult EditUser(string id)
            {
                T_SysUser user;
                if (string.IsNullOrEmpty(id))
                {
                    user = new T_SysUser();
                    user.enabled = true;
                }
                else
                {
                    user = asotsDb.T_SysUser.Where(u => u.userid == id).SingleOrDefault();
                    if (user == null)
                    {
                        throw new Exception("无效的网页地址参数!");
                    }
                }
    
                ViewBag.IsNew = string.IsNullOrEmpty(id);
    
                return View(user);
            }
    
            [HttpPost]
            public ActionResult EditUser(string id, T_SysUser model)
            {
                try
                {
                    if (string.IsNullOrEmpty(model.userid))
                    {
                        ModelState.AddModelError("userid", "用户ID不能为空!");
                    }
    
                    if (string.IsNullOrEmpty(id) && string.IsNullOrEmpty(model.password))
                    {
                        ModelState.AddModelError("password", "密码不能为空!");
                    }
                    else if (!string.IsNullOrEmpty(model.password) && model.password.Length < 6)
                    {
                        ModelState.AddModelError("password","密码字符串长度必需>=6位!");
                    }
    
                    if (string.IsNullOrEmpty(model.employeeid))
                    {
                        ModelState.AddModelError("employeeid", "工号不能为空!");
                    }
    
                    if (string.IsNullOrEmpty(model.realname))
                    {
                        ModelState.AddModelError("realname", "姓名不能为空!");
                    }
    
                    if (ModelState.IsValid)
                    {
                        var loginedUserInfo = UserBusiness.GetLoginedUserInfo();
                        T_SysUser user = asotsDb.T_SysUser.Where(u => u.userid == model.userid).SingleOrDefault();
                        if (string.IsNullOrEmpty(id))
                        {
                            if (user != null)
                            {
                                ModelState.AddModelError("userid", "该用户ID已经存在!");
                            }
                            else
                            {
                                model.password = Common.GetMD5(model.password);
                                model.lasteupdateby = loginedUserInfo["realname"];
                                model.lasteupdatebyid = loginedUserInfo["userid"];
                                model.lastupdatedatetime = DateTime.Now;
                                asotsDb.T_SysUser.InsertOnSubmit(model);
                            }
                        }
                        else
                        {
                            string oldPassword = user.password;
                            UpdateModel(user);
                            user.password = string.IsNullOrEmpty(model.password) ? oldPassword : Common.GetMD5(model.password);
                            user.lasteupdateby = loginedUserInfo["realname"];
                            user.lasteupdatebyid = loginedUserInfo["userid"];
                            user.lastupdatedatetime = DateTime.Now;
                        }
    
                        if (ModelState.IsValid)
                        {
                            asotsDb.SubmitChanges();
                            ViewBag.SuccessMsg = "保存成功!";
                            if (string.IsNullOrEmpty(id))
                            {
                                model = new T_SysUser();
                            }
                        }
                    }
    
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("", ex.Message);
                }
    
                ViewBag.IsNew = string.IsNullOrEmpty(id);
    
                return View(model);
    
            }
    View Code
    @model ASOTS.Models.T_SysUser
               
    @{
        ViewBag.Title = "EditUser";
    
    }
    @using (Html.BeginForm())
    {
    <fieldset>
        <legend>编辑用户信息</legend>
        <table class="edittable">
            <tr>
                <td class="datatile">用户ID:</td>
                <td>
                    @if (ViewBag.IsNew)
                    {
                        @Html.TextBoxFor(m => m.userid, new { @class = "input" })
                    }
                    else
                    {
                         @Html.TextBoxFor(m => m.userid, new { @class = "input", @readonly = "readonly" })
                    }
                    @Html.ValidationMessage("userid")
                </td>
                <td class="datatile">密 码:</td>
                <td>@Html.PasswordFor(m => m.password, new { @class = "input" })
                    @Html.ValidationMessage("password")
                </td>
            </tr>
            <tr>
                <td class="datatile">工 号:</td>
                <td>@Html.TextBoxFor(m => m.employeeid, new { @class = "input" })
                    @Html.ValidationMessage("employeeid")
                </td>
                <td class="datatile">姓 名:</td>
                <td>@Html.TextBoxFor(m => m.realname, new { @class = "input" })
                     @Html.ValidationMessage("realname")
                </td>
            </tr>
            <tr>
                <td class="datatile">职 位:</td>
                <td>@Html.TextBoxFor(m => m.position, new { @class = "input" })</td>
                <td class="datatile">联系电话:</td>
                <td>@Html.TextBoxFor(m => m.telno, new { @class = "input" })</td>
            </tr>
            <tr>
                <td class="datatile">可用否:</td>
                <td>@Html.DropDownListFor(m => m.enabled, new[]{new SelectListItem(){Text="可用",Value="True"},
                                    new SelectListItem(){Text="禁用",Value="False"}}, new { @class = "input" })</td>
                <td></td>
                <td></td>
            </tr>
        </table>
        <p class="btns">
            <input type="submit" value="保 存" class="button" />
        </p>
    </fieldset>
    
    }
    
    @if (ViewBag.SuccessMsg != null)
    {
    <div class="success_box">
        @ViewBag.SuccessMsg
    </div>
    }
    
    @Html.ValidationSummary(true)
    View Code

    原因分析:初步认为是当ModelState中有键值时,在使用View(model)或ViewData.Model=model时,系统自动会将ModelState与model对象进行映射并更新,造成了不论你如何变更model对象的各属性值,最终显示到视图时,仍是显示上次视图界面的值,有点类似webform中的viewstate,当然这个只是我的猜测,若哪位高手知道其原理还望告之。

    解决方案:在重新创建model对象后,1.若要清除model对象中某个属性的值,则可以使用:ModelState.Remove("Model属性名称"),

    2.若要清除model对象所有属性的值,则可以使用:ModelState.Clear()

     

    问题六:使用LINQ TO SQL附加MODEL对象并执行更新或删除时(如:dbDataContext.T_SysUser.Attach(user); dbDataContext.SubmitChanges();),报错:已尝试Attach或Add实体,该实体不是新实体,可能是从其他DataContext中加载来的。不支持这种操作。

     原因分析:详见使用LINQ to SQL更新数据库(上):问题重重

    解决方案:详见使用LINQ to SQL更新数据库(中):几种解决方案,我一直采用的是重新赋值,如下:

    T_SysUser user = asotsDb.T_SysUser.Where(u => u.userid == model.userid).SingleOrDefault();
    UpdateModel(user);

     

    【2014-12-17】 

    问题七:当使用JQuery AJAX POST数组到ACTION时,ACTION无法直接接收该数组信息

    原因分析:用JQuery.Ajax 提交Array的数据,提交的时候始终会在名称后面加上”[]”

    解决方案:1.若是普通的数组,比如:字符串数组、数字数组,则可使用如下方法:

            [HttpPost]
            public ActionResult Test(FormCollection form)
            {
                 string[] userRoles = form.GetValues("params[]");//这里就可以直接获取AJAX POST过来的数组
                
                return View();
            }

    2.若是复杂类型或对象数组,则可使用如下方法:

    [HttpPost]
    public ActionResult Test(FormCollection form)
    {
        var models=form.GetValues("params[]").Select(p=>p.Single<Model>()).ToArray();
    }

    或自定义继承DefaultModelBinder的一个类,并重写BindModel方法:

        public class JQAjaxModelBinder : DefaultModelBinder
        {
    
            public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                if (bindingContext.ModelType.IsArray) //判断是否为数组
                {
                    var key = bindingContext.ModelName + "[]";
                    var valueResult = bindingContext.ValueProvider.GetValue(key);
                    if (valueResult != null && !string.IsNullOrEmpty(valueResult.AttemptedValue))
                    {
                        bindingContext.ModelName = key;
                    }
                }
                return base.BindModel(controllerContext, bindingContext);
            }
        }

    在ACTION中可以如下使用:

            [HttpPost]
            public ActionResult Test([ModelBinder(typeof(JQAjaxModelBinder))] Model[] models)
            {
                 Model model=models[0]; //这里举例获取数组中某个对象
                 model.name="zuowenjun";
                 model.sex=1;
                 model.url="www.zuowenjun.cn";
                return View();
            }

     

    【2015-03-06】

     问题七:ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。

    原因分析:对象的实体状态已处于了 deattach状态;

    解决方案:查询的时候加上asNoTracking(),然后在进行更新或删除时,使用Attach即可;

     

    后续若还有新的问题,会持续更新,工作中学习,学习中总结,总结后实践,实践后掌握!



     
    

     

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-3-29 15:22 , Processed in 0.068376 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表