Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/rest/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ASP.NET Core 2.0 web api实体框架核心-寻找更优雅的解决方案_C#_Rest_Asp.net Web Api_Entity Framework Core_Npgsql - Fatal编程技术网

C# ASP.NET Core 2.0 web api实体框架核心-寻找更优雅的解决方案

C# ASP.NET Core 2.0 web api实体框架核心-寻找更优雅的解决方案,c#,rest,asp.net-web-api,entity-framework-core,npgsql,C#,Rest,Asp.net Web Api,Entity Framework Core,Npgsql,我正在ASP.NET Core 2.0上开发一个web api项目,其中Entity Framework Core连接到postgres数据库 下面的PUT方法可以毫无问题地工作,但我觉得我可能误解了update方法的使用,我还觉得应该有一个更优雅的解决方案来更新现有对象,以一种保存PUT请求而不是补丁的方式 // PUT: api/Discount/5 [HttpPut("{id}")] [ProducesResponseType(204)] [Produces

我正在ASP.NET Core 2.0上开发一个web api项目,其中Entity Framework Core连接到postgres数据库

下面的PUT方法可以毫无问题地工作,但我觉得我可能误解了update方法的使用,我还觉得应该有一个更优雅的解决方案来更新现有对象,以一种保存PUT请求而不是补丁的方式

    // PUT: api/Discount/5
    [HttpPut("{id}")]
    [ProducesResponseType(204)]
    [ProducesResponseType(400)]
    [ProducesResponseType(404)]
    [ProducesResponseType(500)]
    public IActionResult Put(int id, [FromBody]Discount discount)
    {
        if (ModelState.IsValid)
        {
            using (var context = new BarberskabetDbContext())
            {
                if (context.Discounts.Any(x => x.DiscountId == id && !x.Deleted))
                {
                    var dbDiscount = context.Discounts.FirstOrDefault(x => x.DiscountId == id && !x.Deleted);

                    dbDiscount.AppliesOnce = discount.AppliesOnce;
                    dbDiscount.AppliesToProductType = discount.AppliesToProductType;
                    dbDiscount.Code = discount.Code;
                    dbDiscount.DiscountType = discount.DiscountType;
                    dbDiscount.Duration = discount.Duration;
                    dbDiscount.DurationUsageLimit = discount.DurationUsageLimit;
                    dbDiscount.EndsAt = discount.EndsAt;
                    dbDiscount.OncePerCustomer = discount.OncePerCustomer;
                    dbDiscount.RestrictByEmail = discount.RestrictByEmail;
                    dbDiscount.StartsAt = discount.StartsAt;
                    dbDiscount.Status = discount.Status;
                    dbDiscount.TimesUsed = discount.TimesUsed;
                    dbDiscount.UsageLimit = discount.UsageLimit;
                    dbDiscount.Value = discount.Value;

                    context.Update(dbDiscount);
                    if (context.SaveChanges() == 0)
                    {
                        return StatusCode(500, "Unable to update record.");
                    }
                    return NoContent();
                }
                else
                {
                    return NotFound();
                }
            }
        }
        else
        {
            return BadRequest(ModelState);
        }
    }
我觉得应该有更好的方法将新信息放入数据库,但我很难看到它

编辑: 我对优雅/更好的想法是,减少代码以获得相同的效果,并更好地使用工具,正如Ivan正确建议的那样。 感谢所有建议Automapper删除从dto到模型的繁琐的变量重新映射的人。还特别感谢Ivan Stoev解释了强制更新和部分更新的工作原理,并表示最好对异常进行错误处理,而不是受影响的行数。

更新方法用于所谓的强制更新,即断开您确信存在的实体的连接。它不从数据库加载实体,只更新所有属性

以您为例,强制更新如下所示:

if (context.Discounts.Any(x => x.DiscountId == id && !x.Deleted))
{
    context.Update(discount);
    context.SaveChanges();
}
如果要仅更新更改的属性(如果有),则应加载数据库实体并使用CurrentValues.UpdateValues方法应用更改:

var dbDiscount = context.Discounts.FirstOrDefault(x => x.DiscountId == id && !x.Deleted);
if (dbDiscount != null)
{
    context.Entry(dbDiscount).CurrentValues.SetValues(discount);
    context.SaveChanges();
}
请注意,在这种情况下,如果所有属性值都与原始属性值相同,则EF可能根本不会发出update命令,即SaveChanges可以返回0,因此不应将其用作成功的指示。事实上,您不应该将其用于此目的,因为如果出现问题,EF将抛出异常

有关更多信息和示例,请参阅文档主题。

更新方法用于所谓的强制更新,即当您断开实体连接并确定其存在时。它不从数据库加载实体,只更新所有属性

以您为例,强制更新如下所示:

if (context.Discounts.Any(x => x.DiscountId == id && !x.Deleted))
{
    context.Update(discount);
    context.SaveChanges();
}
如果要仅更新更改的属性(如果有),则应加载数据库实体并使用CurrentValues.UpdateValues方法应用更改:

var dbDiscount = context.Discounts.FirstOrDefault(x => x.DiscountId == id && !x.Deleted);
if (dbDiscount != null)
{
    context.Entry(dbDiscount).CurrentValues.SetValues(discount);
    context.SaveChanges();
}
请注意,在这种情况下,如果所有属性值都与原始属性值相同,则EF可能根本不会发出update命令,即SaveChanges可以返回0,因此不应将其用作成功的指示。事实上,您不应该将其用于此目的,因为如果出现问题,EF将抛出异常


有关更多信息和示例,请参阅文档主题。

定义更优雅、更好的。难道你不想看到在那里命名的属性吗?然后使用AutoMapper。如果说“更优雅”是指减少控制器方法中的代码,我会看看AutoMapper。它是一个用于.NET的简单对象/模型映射器。每当我的型号/DTO的尺寸开始显著增长时,我都倾向于使用它。此外,我可能会将CRUD操作分解到解决方案中的另一个类,并在我的控制器中使用存储库模式。难道你不想看到在那里命名的属性吗?然后使用AutoMapper。如果说“更优雅”是指减少控制器方法中的代码,我会看看AutoMapper。它是一个用于.NET的简单对象/模型映射器。每当我的型号/DTO的尺寸开始显著增长时,我都倾向于使用它。此外,我可能会将CRUD操作分解到解决方案中的另一个类,并在我的控制器中使用存储库模式