开发工具与关键技术:Visual Studio 2015 LINQ
作者:孙水兵
撰写时间:2019年6月5
一、 达到的效果
点击修改按钮,弹出修改模态框,并将要修改的线路所在的数据全部回填到修改模态框中,修改之后点击保存即可将修改后的数据保存。
二、 涉及到的表格:线路表(SYS_Circuit)、站点明细表(SYS_StationDetail)
和前面讲过的查询一样,站点明细表中的线路站点类型ID(CircuitStationTypeID)等于1时,表示的站点类型为起点站,站点明细表中的线路站点类型ID(CircuitStationTypeID)等于2时,表示的站点类型为终点站。
三、 代码
修改线路主要修改的还是线路的名称、编号还有起点站和终点站之类的。如果单单要修改的是线路名称之类的,不要修改起点站和终点站,那么这次的修改会很简单。但是由于线路的起点站和终点站都在一个表格中,这样的话修改起来比较麻烦。因此我这里处理的和查询类似,将站点起点站和终点站都分隔开来。
HTML代码
HTML代码中主要注意的是起点站和终点站的name要区分开(不是用ajaxSubmit提交数据的大概可以忽略),其他的可以根据自己的要求来写。至于为什么要在起点站和终点站中加上隐藏的input框?这是为了ajaxSubmit提交数据时可以将站点ID一起提交(也有前提,那就是你前面已经将查询出来的站点ID传入到了其中)。
<div class="modal fade text-right" id="CircuitModal">
<div class="modal-dialog">
<div class="modal-content ">
@*模态框头部*@
<div class="modal-header">
<h5 class="modal-title position-absolute" id="modalCircuitTitle">修改线路详细情况窗口</h5>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span>
<span class="sr-only">Close</span>
</button>
</div>
<div class="modal-body">
<form class="form-horizontal row" role="form" id="formCircuit" action=" " method="post">
@*隐藏域*@
<input type="hidden" name="CircuitID" id="CircuitID" />
<input type="hidden" name="StationDetail" id="StationDetail" />
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">线路编号:</label>
<div class="col-lg-7">
<input type="text" class="form-control" id="CircuitNumber" name="CircuitNumber" autocomplete="off" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">线路名称:</label>
<div class="col-lg-7">
<input type="text" class="form-control" id="CircuitName" name="CircuitName" autocomplete="off" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">起点站:</label>
<div class="col-lg-7">
<input type="hidden" id="StartStationID" name="StartStationID" />
<input type="text" class="form-control" id="StartStationName" name="StartStationName" placeholder="可以输入站点操作码填写站点" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">终点站:</label>
<div class="col-lg-7">
<input type="hidden" id="EndStationID" name="EndStationID" />
<input type="text" class="form-control" id="EndStationName" name="EndStationName" placeholder="可以输入站点操作码填写站点" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">所属车站:</label>
<div class="col-lg-7">
<input type="hidden" id="PassengerStationID" name="PassengerStationID" />
<input type="text" class="form-control" id="PassengerStationName" name="PassengerStationName" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">所属区域:</label>
<div class="col-lg-7">
<input type="hidden" id="AreaID" name="AreaID" />
<input type="text" class="form-control " id="AreaName" name="AreaName" ondblclick="openAreaModal()" placeholder="请双击选择区域" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">里程:</label>
<div class="col-lg-7">
<input type="text" class="form-control" id="CircuitMileage" name="CircuitMileage" autocomplete="off" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">方向:</label>
<div class="col-lg-7">
<input type="text" class="form-control" id="CircuitDirection" name="CircuitDirection" autocomplete="off" />
</div>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<div class="col-3"></div>
<input type="checkbox" class="mr-1 ml-2" id="CircuitToVoidNo" name="CircuitToVoidNo" style="margin-top:10px;" />
<label class="col-form-label" for="CircuitToVoidNo">是否停用</label>
</div>
</div>
<div class=" row p-0 m-0 w-100">
<div class="form-group form-row w-100">
<label class="col-form-label col-lg-3">备注:</label>
<div class="col-lg-7">
<input type="text" class="form-control" id="CircuitRemark" name="CircuitRemark" autocomplete="off" />
</div>
</div>
</div>
<div class="modal-footer justify-content-center w-100">
<button type="button" class="btn btn-primary" id="btnSaveCircuit">确认</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
</div>
</form>
</div>
</div>
</div>
</div>
JS代码
和之前写的linq修改类似,可以查看我之前的文章linq修改,建议先查看了linq修改在来查看此文章。
//保存新增/修改
$("#btnSaveCircuit").click(function () {
layIndex = layer.load();
$("#formCircuit").ajaxSubmit(function (data) {
layer.close(layIndex);
if (data.State) {
//关闭模态框
$("#CircuitModal").modal('hide');
tabCircuit.reload();
layer.alert(data.Text, { icon: 1, title: "提示" });
} else {
layer.alert(data.Text, { icon: 2, title: "提示" });
}
})
})
控制器代码—接收数据
控制器接收页面传过来的数据主要还是根据前面查询的时候新建的一个实体类(CircuitVo),前提是view中相对应的input框的name要与CircuitVo中的一致。而之后的sysCuit是用来接收线路表中相对应的数据处理之后要保存的数据。后面两个也类似,statrtsysStationDetail是要保存进站点明细表中的起点站的数据,EndsysStationDetail是要保存进站点明细表中的终点站的数据。
保存站点
线路数据的处理很简单,在这就不多说了,主要的还是起点站和终点站的处理。再保存完修改之后的线路之后,就是处理站点了。声明一个变量CircuitID用来接收要修改线路的ID。然后从站点明细表中查询出要修改的线路中起点站所在的那条数据的信息(线路ID等于要修改的线路ID,并且线路站点类型ID=1的即为要修改的线路中起点站所在的那条数据),至于为什么要在Single()之前加上AsNoTracking(),后面会说。查询完数据之后,将查询出来的站点明细表中的站点明细ID给要保存的的站点明细ID。然后for循环,在for循环中判断,如果i等于0,就处理起点站的数据,否则,就处理终点站的数据。然后保存起点站的数据,保存完起点站的数据之后再处理终点站并保存。终点站保存成功之后就表示修改成。
public ActionResult updateCircuit(CircuitVo CircuitInfo, SYS_Circuit sysCircuit, SYS_StationDetail statrtsysStationDetail, SYS_StationDetail EndsysStationDetail)
{
ReturnJsonVo returnJson = new ReturnJsonVo();
//开启事务
using (var scope = new TransactionScope())
{
try
{
if (!string.IsNullOrEmpty(CircuitInfo.CircuitName) && !string.IsNullOrEmpty(CircuitInfo.CircuitNumber)
&& !string.IsNullOrEmpty(CircuitInfo.StartStationName) && !string.IsNullOrEmpty(CircuitInfo.EndStationName)
&& !string.IsNullOrEmpty(CircuitInfo.CircuitDirection) && !string.IsNullOrEmpty(CircuitInfo.PassengerStationName)
&& !string.IsNullOrEmpty(CircuitInfo.AreaName) && CircuitInfo.CircuitMileage > 0)
{
var linqCircuit = from tbStationDetail in myModels.SYS_StationDetail
orderby tbStationDetail.CircuitStationTypeID ascending
group tbStationDetail by tbStationDetail.CircuitID into tbStation
select new
{
CircuitID = tbStation.Key,
StartStationID = tbStation.FirstOrDefault().StationID,
EndStationID = tbStation.OrderByDescending(m => m.CircuitStationTypeID).FirstOrDefault().StationID,
};
int CircuitCount = (from tbCircuit in myModels.SYS_Circuit
where tbCircuit.CircuitID != CircuitInfo.CircuitID && (tbCircuit.CircuitNumber.Trim() == CircuitInfo.CircuitNumber.Trim()
|| tbCircuit.CircuitName.Trim() == CircuitInfo.CircuitName.Trim())
select tbCircuit).Count();
if (CircuitCount == 0)
{
// Distinct() 去除查询出来的重复的数据
var StationCount = (from tblinqCircuit in linqCircuit
join tbCitcuit in myModels.SYS_Circuit on tblinqCircuit.CircuitID equals tbCitcuit.CircuitID
where tbCitcuit.CircuitID != CircuitInfo.CircuitID && (tbCitcuit.CircuitID == tblinqCircuit.CircuitID && (
tblinqCircuit.StartStationID == CircuitInfo.StartStationID && tblinqCircuit.EndStationID == CircuitInfo.EndStationID))
select tblinqCircuit).Distinct().Count();
if (StationCount == 0)
{
Boolean CircuitToVoidNo = Convert.ToBoolean(Session["CircuitToVoidNo"].ToString());
sysCircuit.AreaID = CircuitInfo.AreaID;
sysCircuit.PassengerStationID = CircuitInfo.PassengerStationID;
sysCircuit.CircuitName = CircuitInfo.CircuitName;
sysCircuit.CircuitNumber = CircuitInfo.CircuitNumber;
sysCircuit.CircuitMileage = CircuitInfo.CircuitMileage;
sysCircuit.CircuitDirection = CircuitInfo.CircuitDirection;
sysCircuit.CircuitRemark = CircuitInfo.CircuitRemark;
sysCircuit.CircuitToVoidNo = CircuitToVoidNo;
myModels.Entry(sysCircuit).State = EntityState.Modified;
if (myModels.SaveChanges() > 0)
{
var CircuitID = sysCircuit.CircuitID;
var StartstationDetailID = (from tbStationDetail in myModels.SYS_StationDetail
where tbStationDetail.CircuitID == CircuitID && tbStationDetail.CircuitStationTypeID == 1
select tbStationDetail).AsNoTracking().Single();
statrtsysStationDetail.StationDetailID = StartstationDetailID.StationDetailID;
for (int i = 0; i < 2; i++)
{
if (i == 0)
{
statrtsysStationDetail.CircuitID = CircuitID;
statrtsysStationDetail.StationID = CircuitInfo.StartStationID;
statrtsysStationDetail.CircuitStationTypeID = 1;
}
else
{
EndsysStationDetail.CircuitID = CircuitID;
EndsysStationDetail.StationID = CircuitInfo.EndStationID;
EndsysStationDetail.CircuitStationTypeID = 2;
}
}
myModels.Entry(statrtsysStationDetail).State = EntityState.Modified;
if (myModels.SaveChanges() > 0)
{
var EndstationDetailID = (from tbStationDetail in myModels.SYS_StationDetail
where tbStationDetail.CircuitID == CircuitID && tbStationDetail.CircuitStationTypeID == 2
select tbStationDetail).AsNoTracking().Single();
EndsysStationDetail.StationDetailID = EndstationDetailID.StationDetailID;
myModels.Entry(EndsysStationDetail).State = EntityState.Modified;
if (myModels.SaveChanges() > 0)
{
//提交事务
scope.Complete();
returnJson.State = true;
returnJson.Text = "修改成功!";
}
else
{
returnJson.Text = "修改失败!";
}
}
}
else
{
returnJson.Text = "线路修改失败!";
}
}
else
{
returnJson.Text = "该线路已存在!";
}
}
else
{
returnJson.Text = "线路编号或线路名称一致!";
}
}
else
{
returnJson.Text = "请填写完整!";
}
}
catch (Exception e)
{
Console.Write(e);
returnJson.Text = "参数异常!";
}
}
return Json(returnJson, JsonRequestBehavior.AllowGet);
}
四、 出现的异常
1、
翻译过来为:因为相同类型的其他实体已具有相同的主键值。在使用 “Attach” 方法或者将实体的状态设置为 “Unchanged” 或 “Modified” 时如果图形中的任何实体具有冲突键值,则可能会发生上述行为。这可能是因为某些实体是新的并且尚未接收数据库生成的键值。在此情况下,使用 “Add” 方法或者 “Added” 实体状态跟踪该图形,然后将非新实体的状态相应设置为 “Unchanged” 或 “Modified”。
出现异常的地方:
原因与解决方法:(来源于网上)
我们查询出的数据会被缓存system.data.entity.dbcontext中,这个对象是会被跟踪的。所以,使我正在加载的对象不被跟踪,或者说不被缓存到system.data.entity.dbcontext中即可。因此使用了方法AsNoTracking():返回一个新的查询,其中返回的实体不会缓存在System.Data.Entity.DbContext中System.Data.Entity.Core.Objects.ObjectContext。
2、
翻译过来为:存储更新、插入或删除语句会影响意外的行数(0)。自加载实体以来,可能已经修改或删除了实体。参见http://go.microsoft.com/fwlink/?有关理解和处理乐观并发异常的信息,请参阅LinkId=472540。
原因与解决方法: 修改时实体类的主键未赋值。解决方法:给实体类的主键未赋值