您好社区,我正在尝试更新主类中的辅助数据,主类为 body * {
box-sizing: border-box !important;
}
.history-img{
width: 60px;
height: 60px;
object-fit: cover;
object-position: center;
}
.scrolling-wrapper{
max-height: 700px !important;
flex-wrap: wrap !important;
}
.card{
width: 20%;
height: 200px !important;
margin: 0;
}
,其中的quotation
类包含对另外两个类的引用,{{1 }}类和cart
。
我现在可以更新报价类的属性,并设法在报价中插入新商品,但是当插入新产品时,购物车ID变为空,在数据库的商品购物车表中,我具有商品ID和ID购物车。
如何更新报价中的产品?
如何防止cart articles
变为空?
这是我的代码:
products
CarritoId
为空,我不希望发生这种情况
答案 0 :(得分:1)
如何防止CarritoId变为空?
最终不通过在控制器,视图和返回之间传递实体。看起来您正在向视图中发送实体,并且该实体正在Put中发送回去,但是您要发送的是序列化的JSON块并将其强制转换为实体。这样做会导致类似的问题,其中您的Model变成了实体图的序列化,当您开始将其附加到DbContext上以作为实体进行跟踪时,该图可能会丢失并丢失。您可能会遇到这种情况,发送给视图的数据不完整,或者通过附加顶层,您期望所有相关实体都将被附加和跟踪,但这种情况并不常见。更改FK参考也可能导致意外结果,而不是更新可用的导航属性。它还使您的应用程序容易受到篡改,因为恶意客户端或浏览器加载项可以修改发送到服务器的数据,以调整UI甚至不显示的值。现代的浏览器调试工具使这项工作变得非常简单。
理想情况下,控制器和视图应基于加载的实体与视图模型进行通信。这也可以简化传送的数据量,以减小有效负载大小。
为帮助缓解这种情况,请像对待方法未接收实体一样进行处理。无论如何,您都将再次加载该实体,但在这种情况下,除了再次分离它以尝试附加传入的JSON对象之外,您什么都不做。例如此代码:
var cotizacionoriginal = context.Cotizaciones.Where(x => x.CotizacionId == cotizacion.CotizacionId).FirstOrDefault();
if (cotizacionoriginal != null)
{
context.Entry(cotizacionoriginal).State = EntityState.Detached;
}
...绝对不会为您做任何事情。它说:“尝试在本地缓存或数据库中找到具有此ID的对象,如果找到它,则停止跟踪它。”
您无故有效地进入了数据库。这甚至不能断言该行存在,因为您使用的是“ OrDefault”变体。
一开始,它应显示为:
var cotizacionoriginal = context.Cotizaciones
.Where(x => x.CotizacionId == cotizacion.CotizacionId)
.Single();
这是“从具有此CotizacionId的本地缓存或数据库中加载一行”。这断言数据库中实际上存在匹配的行。如果传递到Put的记录的ID无效,则将引发异常。我们不想要分离它。
更多细节。由于我们要在此对象中操作子集合和引用,因此我们应该急于加载它们:
var cotizacionoriginal = context.Cotizaciones
.Include(x => x.Carriyo)
.ThenInclude(c => c.Articulo)
.ThenInclude(a => a.Producto)
.Where(x => x.CotizacionId == cotizacion.CotizacionId).Single();
对于较大的对象图,这可能会变得很罗word,因为您必须向下钻取每个相关实体链。更好的方法不是立即更新“整个”对象图,而是将其分解为较小的合法操作,一次可以处理一个实体关系。
下一步将是验证Put对象中传递的值。它看起来是完整的还是有什么不合适?至少我们应该检查当前的会话用户ID,以验证他们是否有权访问此已加载的Cortizacion行并有权对其进行编辑。如果不是,则抛出异常。网站的异常处理应确保记录任何严重的异常,例如尝试访问不存在或没有权限的行,以供管理员检查,并且当前会话应结束。可能有人在篡改系统,或者您有一个错误,可能会导致数据损坏。无论哪种方式,都应该对其进行检测,报告和修复,以防当前会话终止。
最后一步是浏览传入的对象图,并更改您的“原始”数据以使其匹配。再次重要的是,您不能信任/处理作为“实体”传入的参数,只能信任看起来像实体的反序列化数据。因此,如果产品在其中一个参考项目中发生更改,我们将获取一个参考并进行更新。
foreach (ArticuloCarrito articulo in cotizacion.Carrito.Articulos)
{
if (articulo.ArticuloId == 0)
{ // TODO: Handle adding a new article if that is supported.
}
else
{
var existingArticulo = existingCarrito.Articulos.Single(x => x.ArticuloId == articulo.ArticuloId);
if (existingArticulo.ProductoId != articulo.Producto.ProductoId)
{
var producto = context.Productos.Single(x => x.ProductoId == articulo.Producto.ProductoId);
existingArticulo.Producto = producto;
}
}
}
await context.SaveChangesAsync();
可选地,在上面我们可以检查Articulo以查看是否添加了新行。 (尚无ID)如果我们有ID,请检查现有的Carrito商品是否有匹配的商品。如果找不到,则将导致异常。拥有一个后,我们将检查产品ID是否已更改。如果已更改,我们将不使用传入的“ Producto”,因为这是反序列化的JSON对象,因此我们转到Context加载引用并将其设置在现有行上。
上下文。SaveChanges
每次操作仅应调用一次,而不是在循环内调用。
将值从分离的反序列化实体复制到跟踪实体时,可以使用:
context.Entry(existingArticulo).CurrentValues.SetValues(articulo);
但是,仅当传入的对象中的值经过验证时,才应执行此操作。据我所知,这仅更新值字段,而不更新FK或对象引用。
希望这能为您提供一些思路,以尝试简化更新过程。