最近一直用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开发设计中出现的问题与解决方案汇总 【持续更新】的更多相关文章

  1. ASP.NET MVC开发学习过程中遇到的细节问题以及注意事项

    1.datagrid中JS函数传值问题: columns: { field: 'TypeName', title: '分类名称', width: 120, sortable: true, format ...

  2. Salesforce 开发整理(九) 开发中使用的一些小技巧汇总[持续更新]

    1.查询一个对象下所有字段 当需要查询一个对象所有字段进行复制或其他操作,可以使用一段拼接的语句来查询 String query = 'select '; for(String fieldApi : ...

  3. vsCode开发java遇到的问题整理、解决方案(持续更新)

    获取控制台输入的信息: 休息launch.json文件中的console属性internalConsole(内部控制台)修改为externalTerminal(外部控制台)即可正常获取输入信息,代码如 ...

  4. ASP.NET MVC开发:Web项目开发必备知识点

    最近加班加点完成一个Web项目,使用Asp.net MVC开发.很久以前接触的Asp.net开发还是Aspx形式,什么Razor引擎,什么MVC还是这次开发才明白,可以算是新手. 对新手而言,那进行A ...

  5. 基于C#和Asp.NET MVC开发GPS部标视频监控平台

    基于C#和Asp.NET MVC开发GPS部标监控平台 目前整理了基于.NET技术的部标平台开发文章,可以参考: 1.部标Jt808协议模拟终端的设计和开发 2.C#版的808GPS服务器开发-> ...

  6. 如何在ASP.NET MVC和EF中使用AngularJS

    (此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) AngularJS作为一个越来越流行的前端框架,在使用ASP.NET MVC和实体框架开发W ...

  7. T4 模板 : 一种提升ASP.NET MVC开发速度方法

    最近由于需要在框架中提供一些自定义模板的功能,找到了一篇博客,可惜似乎是翻译工具直接翻的,读不通顺,就试着自己翻译下,我不会完全翻译原文的句子,可能会对原文进行小范围的我认为更合适的句子并添加些注释, ...

  8. 解析ASP.NET Mvc开发之删除修改数据

    目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 4)解析ASP.NET Mvc开发之EF延迟加载 ...

  9. 在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能

    在ASP.NET MVC应用程序中,如果使用Server.Transfer()方法希望将请求转发到其它路径或者Http处理程序进行处理,都会引发“为xxx执行子请求时出错”的HttpException ...

随机推荐

  1. ubuntu11.10搭建eclipse C++开发环境[zhuan]

    1.最重要的东西,C++必要工具,安装的是GCC工具链,Make等一系列开发工具: sudo apt-get install build-essential 2. 安装Eclipse sudo apt ...

  2. c# 小数取整

    向上取整 math.ceiling() = math.ceiling( math.ceiling( 向下取整 math.) = math. math. C#取整函数实例应用详解 C#取整函数的相关使用 ...

  3. struts1+spring+myeclipse +cxf 开发webservice以及普通java应用调用webservice的实例

    Cxf + Spring+ myeclipse+ cxf 进行  Webservice服务端开发 使用Cxf开发webservice的服务端项目结构 Spring配置文件applicationCont ...

  4. ubuntu下取代ping的好工具tcpping

    $ sudo apt-get install tcptraceroute bc$ cd /usr/bin$ sudo wget http://www.vdberg.org/~richard/tcppi ...

  5. 手动安装 atom 扩展包 packages

    由于某些原因, 我们下载 atom 扩展时发现速度特别慢, 或者根本无法下载, 那我们可以尝试手动安装 首先, 从 github 上下载(或其它地方) 扩展包, 解压 进入该文件夹, 找到 packa ...

  6. The model backing the <Database> context has changed since the database was created.

    Just found out the answer and thought of updating here. Just need to do the following. public class ...

  7. How to get the Current Controller Name, Action, or ID in ASP.NET MVC

    public static class HtmlRequestHelper { public static string Id(this HtmlHelper htmlHelper) { var ro ...

  8. Spark源码系列(七)Spark on yarn具体实现

    本来不打算写的了,但是真的是闲来无事,整天看美剧也没啥意思.这一章打算讲一下Spark on yarn的实现,1.0.0里面已经是一个stable的版本了,可是1.0.1也出来了,离1.0.0发布才一 ...

  9. 为Ubuntu笔记本电脑设置WiFi热点共享上网

    该文由土木坛子转译而来,说是转译,其实看截图就可以方便的设置,没有任何命令,全是图形界面,方便容易.我们都知道怎样在 windows 7 系统上如何设计 Wifi 热点,当你只有一条网线,多台计算机的 ...

  10. 国行手机安装GOOGLE PLAY

    原文地址:http://blog.sina.com.cn/s/blog_68cff87b0101a96k.html 相信国行的手机都是没有google Play 功能的吧,相比其它国外的手机,功能上逊 ...