关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】
最近一直用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 < )
{
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); }
@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)
原因分析:初步认为是当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[]; //这里举例获取数组中某个对象
model.name="zuowenjun";
model.sex=;
model.url="www.zuowenjun.cn";
return View();
}
【2015-03-06】
问题七:ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
原因分析:对象的实体状态已处于了 deattach状态;
解决方案:查询的时候加上asNoTracking(),然后在进行更新或删除时,使用Attach即可;
后续若还有新的问题,会持续更新,工作中学习,学习中总结,总结后实践,实践后掌握!
关于ASP.NET MVC开发设计中出现的问题与解决方案汇总 【持续更新】的更多相关文章
- ASP.NET MVC开发学习过程中遇到的细节问题以及注意事项
1.datagrid中JS函数传值问题: columns: { field: 'TypeName', title: '分类名称', width: 120, sortable: true, format ...
- Salesforce 开发整理(九) 开发中使用的一些小技巧汇总[持续更新]
1.查询一个对象下所有字段 当需要查询一个对象所有字段进行复制或其他操作,可以使用一段拼接的语句来查询 String query = 'select '; for(String fieldApi : ...
- vsCode开发java遇到的问题整理、解决方案(持续更新)
获取控制台输入的信息: 休息launch.json文件中的console属性internalConsole(内部控制台)修改为externalTerminal(外部控制台)即可正常获取输入信息,代码如 ...
- ASP.NET MVC开发:Web项目开发必备知识点
最近加班加点完成一个Web项目,使用Asp.net MVC开发.很久以前接触的Asp.net开发还是Aspx形式,什么Razor引擎,什么MVC还是这次开发才明白,可以算是新手. 对新手而言,那进行A ...
- 基于C#和Asp.NET MVC开发GPS部标视频监控平台
基于C#和Asp.NET MVC开发GPS部标监控平台 目前整理了基于.NET技术的部标平台开发文章,可以参考: 1.部标Jt808协议模拟终端的设计和开发 2.C#版的808GPS服务器开发-> ...
- 如何在ASP.NET MVC和EF中使用AngularJS
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) AngularJS作为一个越来越流行的前端框架,在使用ASP.NET MVC和实体框架开发W ...
- T4 模板 : 一种提升ASP.NET MVC开发速度方法
最近由于需要在框架中提供一些自定义模板的功能,找到了一篇博客,可惜似乎是翻译工具直接翻的,读不通顺,就试着自己翻译下,我不会完全翻译原文的句子,可能会对原文进行小范围的我认为更合适的句子并添加些注释, ...
- 解析ASP.NET Mvc开发之删除修改数据
目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 4)解析ASP.NET Mvc开发之EF延迟加载 ...
- 在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能
在ASP.NET MVC应用程序中,如果使用Server.Transfer()方法希望将请求转发到其它路径或者Http处理程序进行处理,都会引发“为xxx执行子请求时出错”的HttpException ...
随机推荐
- JSP 处理汉字信息
request 对象获取客户端提交的汉字字符时,会出现乱码问题,所以对含有汉字字符的信息必须进行特殊处理.将获取的字符串用 ISO-8859-1 进行编码,并将编码存放到一个字节数组中,再将这个数组转 ...
- Debug Assertion Failed! Expression: _pFirstBlock == pHead
点击Abort之后,查看调用栈,发现异常在函数return时被时产生,进一步看是vector的析构函数被调用时产生,以前没开发过C++项目,没什么经验,这个错误让我很困惑,第一,我电脑上并没有f盘:第 ...
- Git Tips
撤销已经推送到远程仓库的最后一次提交,要小心这么操作,因为远程仓库还有别人在使用 $ git reset --hard HEAD^ $ git push -f origin master 从仓库中提出 ...
- [ITSEC]信息安全·Web安全培训第一期客户端安全之UBB系列
缩略图: 引文: 所谓UBB代码,是指论坛中的替代HTML代码的安全代码.ubb发帖编辑器 这种代码使用正则表达式来进行匹配,不同的论坛所使用的UBB代码很可能不同,不能一概而论.UBB代码的出现,使 ...
- 使用BAT批处理执行sql语句的代码
使用BAT批处理执行sql语句的代码 有时候需要执行一些Sql语句时,不想开企业管理器,或者是发给客户执行但那边又不懂代码,这时就可以用下面方法 1.把待执行Sql保存在一个文件,这里为2011022 ...
- Volley 实现原理解析(转)
Volley 实现原理解析 转自:http://blog.csdn.net/fengqiaoyebo2008/article/details/42963915 1. 功能介绍 1.1. Volley ...
- XCode使用自带SVN,SVN命令
转载http://blog.sina.com.cn/s/blog_68661bd80101phpy.html 这两天响应老板要求,把所有代码放到公司的SVN服务器上,按照我的想法肯定是就苹果组建一个服 ...
- Oracle数据库入门——物化视图语法
一.Oracle物化视图语法 create materialized view [view_name]refresh [fast|complete|force][on [commit|demand] ...
- 在自己的对象里实现IEnumerator和IEnumerable
平时工作中我们经常用foreach来迭代一个集合.比如 foreach (Student student in myClass) { Console.WriteLine(student); } 基本所 ...
- JavaScript高级之词法作用域和作用域链
主要内容: 分析JavaScript的词法作用域的含义 解析变量的作用域链 变量名提升时什么 一.关于块级作用域 说到JavaScript的变量作用域,与咱们平时使用的类C语言不同. ...