简体   繁体   English

在 EF 核心中执行部分更新并且从不更新某些属性的最佳方法是什么?

[英]What is the best way to perform partial updates in EF core and never update certain properties?

I know you can do something like var myObj = _db.MyTable.FirstOrDefault(x=>x.Id==id) and then update myObj property by property that you want to update but is there a better way to update say 6 out of 10 properties of myObj and leave the other 4 alone or have them marked as a way that they are only set once and never updateable from ef core?我知道您可以执行类似 var myObj = _db.MyTable.FirstOrDefault(x=>x.Id==id) ,然后按要更新的属性更新myObj属性,但是有没有更好的方法来更新其中的 6 个myObj 10 个属性并保留其他 4 个属性,或者将它们标记为仅设置一次且永远无法从 ef core 更新的方式?

    public class MyObject
{
    public string Id { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
    public string Prop4 { get; set; }
    public string Prop5 { get; set; }
    public string Prop6 { get; set; }
    public string Prop7 { get; set; }
    public string Prop8 { get; set; }
    public string Prop9 { get; set; }

}

       public void UpdateObj(MyObject ojToUpdate)
    {
        //Is there a better way to write this function if you only want to update a set amount of properties
        var myObj = _db.MyObject.First(x=>x.Id==ojToUpdate.Id);
        myObj.Prop1 = objToUpdate.Prop1;
        myObj.Prop2 = objToUpdate.Prop2;
        myObj.Prop3 = objToUpdate.Prop3;
        myObj.Prop4 = objToUpdate.Prop4;
        myObj.Prop5 = objToUpdate.Prop5;
        myObj.Prop6 = objToUpdate.Prop6;
        _db.SaveChanges();
    }

Obviously you can write something like _db.MyObject.Update(objToUpdate) .显然,您可以编写类似_db.MyObject.Update(objToUpdate) The problem with this statement is the user can update prop 4/5/6 which I don't want them to update.此语句的问题是用户可以更新我不希望他们更新的道具 4/5/6。 Yes I know you can write _db.Entry(myObj).CurrentValues.SetValues(objToUpdate) and then call save changes but that will over ride properties that i want to be generated once and never modified again.是的,我知道您可以编写_db.Entry(myObj).CurrentValues.SetValues(objToUpdate)然后调用保存更改,但这会覆盖我想要生成一次并且不再修改的属性。

Thanks ahead of time.提前致谢。

Starting with EF Core 2.0, you can use IProperty.AfterSaveBehavior property:从 EF Core 2.0 开始,您可以使用IProperty.AfterSaveBehavior属性:

Gets a value indicating whether or not this property can be modified after the entity is saved to the database.获取一个值,该值指示在将实体保存到数据库后是否可以修改此属性。

If Throw , then an exception will be thrown if a new value is assigned to this property after the entity exists in the database.如果是Throw ,则在实体存在于数据库中后,如果为此属性分配了新值,则会引发异常。

If Ignore , then any modification to the property value of an entity that already exists in the database will be ignored.如果忽略,则对数据库中已存在的实体的属性值的任何修改都将被忽略。

What you need is the Ignore option.您需要的是Ignore选项。 At the time of writing there is no dedicated fluent API method for that, but Setting an explicit value during update contains an example how you can do that.在撰写本文时,还没有专门的 fluent API 方法,但在更新期间设置显式值包含一个示例,您可以如何做到这一点。

Taking your example, something like this:以你的例子为例,像这样:

modelBuilder.Entity<MyObject>(builder =>
{
    builder.Property(e => e.Prop7).Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
    builder.Property(e => e.Prop8).Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
    builder.Property(e => e.Prop9).Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
});

Now both现在两者

public void UpdateObj(MyObject objToUpdate)
{
    var myObj = _db.MyObject.First(x => x.Id == objToUpdate.Id);
    _db.Entry(myObj).CurrentValues.SetValues(myObjToUpdate);
    _db.SaveChanges();
}

and

public void UpdateObj(MyObject objToUpdate)
{
    _db.Update(myObjToUpdate);
    _db.SaveChanges();
}

will ignore Prop7 , Prop8 and Prop9 values of the passed myObjToUpdate .会忽略Prop7Prop8Prop9传递的价值观myObjToUpdate

Update (EF Core 3.0+) The aforementioned property has been replaced with GetAfterSaveBehavior and SetAfterSaveBehavior extension methods.更新(EF Core 3.0+)上述属性已替换为GetAfterSaveBehaviorSetAfterSaveBehavior扩展方法。

If you have an entity:如果您有实体:

public class Person
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Address { get; set; }
}

And you run:你运行:

var p = ctx.Person.First();
p.Name = "name updated";
ctx.SaveChanges();

EF will generate the following SQL statement: EF将生成以下 SQL 语句:

在此处输入图片说明

You can verify it using SQL Server Profiler , the same is true if you update 6/10 properties.您可以使用SQL Server Profiler验证它,如果您更新 6/10 属性也是如此。

You can also in your dbContext inside the OnModelCreating use before mentioned AfterSaveBehavior like this:你也可以在你的 dbContext 里面的 OnModelCreating 使用之前提到的 AfterSaveBehavior 像这样:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{

modelBuilder.Entity<someobject>(builder =>
{
    builder.Property(i => i.CreatedAt).Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
});

Now the "CreatedAt" property on "someobject" will be saved first time, and then never modified on future updates.现在,“someobject”上的“CreatedAt”属性将第一次保存,然后在以后的更新中永远不会修改。

As of 3.1, this can be accomplished by using the SetAfterSaveBehavior() extension method:从 3.1 开始,这可以通过使用 SetAfterSaveBehavior() 扩展方法来完成:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<someobject>(builder =>
{
    builder.Property(i => i.CreatedAt).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
});

https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.mutablepropertyextensions.setaftersavebehavior?view=efcore-3.1 https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.mutablepropertyextensions.setaftersavebehavior?view=efcore-3.1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM