调用 SaveChanges() 时排除更新属性

2024-02-21

似乎有两种方法可以使用“附加”方法来更新断开连接的实体框架实体。

方法一是简单地将断开连接的实体的状态设置为已修改:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;
myDbContext.SaveChanges();

这将保存“dog”对象上的所有字段。但是假设您是从 mvc 网页执行此操作,其中只允许编辑 Dog.Name,并且页面上包含的唯一 Dog 属性是 Name。那么可以采用方法二:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).Property(o => o.Name).CurrentValue = dog.Name;
myDbContext.Entry(dog).Property(o => o.Name).IsModified = true;
myDbContext.SaveChanges();

当有很多属性需要更新时,方法二可能会变得非常冗长。这促使我尝试方法三,在我不想更改的属性上设置 IsModified = false。这不起作用,抛出运行时错误“不支持将 IsModified 设置为 false 来修改属性”:

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;
myDbContext.Entry(dog).Property(o => o.Owner).IsModified = false;
myDbContext.SaveChanges();

我更喜欢在任何地方都使用方法一,但在很多情况下,我的 asp.net mvc 视图并不包含 Dog 类的每个标量属性。

我的问题是:

  1. 我可以在 POCO 类上使用任何属性来告诉实体框架我永远不希望更新该属性吗?例如,[从不更新]。我知道 [NotMapped] 属性,但这不是我需要的。
  2. 如果失败的话,有什么办法可以使用上面的方法一(myDbContext.Entry(dog).State = EntityState.Modified; )并排除我不想更新的字段?

附:我知道另一种方法,不使用“附加”,而是简单地从数据库中获取新对象,更新所需的属性,然后保存。这就是我正在做的事情,但我很好奇是否有一种方法可以使用“附加”,从而避免对数据库的额外访问,但以一种不像上面方法二那么冗长的方式进行。我所说的“获取一个新的对象”是指:

Dog dbDog = myDbContext.Dogs.FirstOrDefault(d => d.ID = dog.ID);
dbDog.Name = dog.Name;
myDbContext.SaveChanges();

以下可能有效有效。

myDbContext.Dogs.Attach(dog);
myDbContext.Entry(dog).State = EntityState.Modified;

var objectContext = ((IObjectContextAdapter) myDbContext).ObjectContext;
foreach (var entry in objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Where(entity => entity.Entity.GetType() == typeof(Dogs)))
{
    // You need to give Foreign Key Property name
    // instead of Navigation Property name
    entry.RejectPropertyChanges("OwnerID"); 

}

myDbContext.SaveChanges();

如果您想在一行中完成,请使用以下扩展方法:

public static void DontUpdateProperty<TEntity>(this DbContext context, string propertyName)
{
    var objectContext = ((IObjectContextAdapter) context).ObjectContext;
    foreach (var entry in objectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Where(entity => entity.Entity.GetType() == typeof(TEntity)))
    {
        entry.RejectPropertyChanges(propertyName); 
    }
}

像这样使用它

// After you modify some POCOs
myDbContext.DontUpdateProperty<Dogs>("OwnerID");
myDbContext.SaveChanges();

如您所见,您可以修改此解决方案以满足您的需求,例如使用string[] properties代替string propertyName作为论点。


建议的方法

更好的解决方案是按照您的建议使用属性([NeverUpdate])。为了使其工作,您需要使用 SavingChanges 事件(检查我的blog https://helicoder.wordpress.com/2013/07/20/execute-code-before-save-and-after-fetch-in-entity-framework/):

void ObjectContext_SavingChanges(object sender, System.Data.Objects.SavingChangesEventArgs e)
{
    ObjectContext context = sender as ObjectContext;
    if(context != null)
    {
        foreach(ObjectStateEntry entry in context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
        {
            var type = typeof(entry.Entity);
            var properties = type.GetProperties();
            foreach( var property in properties )
            {
                var attributes = property.GetCustomAttributes(typeof(NeverUpdateAttribute), false);
                if(attributes.Length > 0)
                    entry.RejectPropertyChanges(property.Name);
            }
        }
    }
}
// Check Microsoft documentation on how to create custom attributes:
// http://msdn.microsoft.com/en-us/library/sw480ze8(v=vs.80).aspx
public class NeverUpdateAttribute: SystemAttribute
{

}

//In your POCO
public class Dogs
{
    [NeverUpdate]
    public int OwnerID { get; set; }
}

警告:我没有编译此代码。我不在家:/


警告2:我刚刚读过MSDN 文档 http://msdn.microsoft.com/en-us/library/system.data.objects.objectstateentry.rejectpropertychanges.aspx它说:

ObjectStateEntry.RejectPropertyChanges 方法

拒绝自以下时间以来对具有给定名称的属性所做的任何更改 属性是最后加载的,attached、已保存或更改已被接受。属性的原始值将被存储,并且该属性将不再被标记为已修改。

我不确定在附加修改的实体的情况下它的行为会是什么。明天我会尝试这个。 罢工>


警告3: 我现在已经尝试过了。这个解决方案有效。被拒绝的财产RejectPropertyChanges()方法不会在持久性单元(数据库)中更新。

HOWEVER,如果更新的实体是通过调用附加的Attach(),当前上下文在之后仍然是脏的SaveChanges()。假设数据库中存在以下行:

Dogs
ID: 1
Name: Max
OwnerID: 1

考虑以下代码:

var myDog = new Dogs();
myDog.ID = 1;
myDog.Name = Achilles;
myDog.OwnerID = 2;

myDbContext.Dogs.Attach(myDog);
myDbContext.Entry(myDog).State = EntityState.Modified;
myDbContext.SaveChanges();

SaveChanges() 之后数据库的当前状态:

Dogs:
ID: 1
Name: Achilles
OwnerID: 1

SaveChanges() 之后 myDbContext 的当前状态:

var ownerId = myDog.OwnerID;  // it is 2
var status = myDbContext.Entry(myDog).State; // it is Unchanged

那么你应该做什么?在 SaveChanges() 之后将其分离:

Dogs myDog = new Dogs();
//Set properties
...
myDbContext.Dogs.Attach(myDog);
myDbContext.Entry(myDog).State = EntityState.Modified;
myDbContext.SaveChanges();
myDbContext.Entry(myDog).State = EntityState.Detached;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

调用 SaveChanges() 时排除更新属性 的相关文章

随机推荐

  • 如何设置搜查排序的默认值?

    简而言之 我只是想知道是否有办法使用 Ransack gem 设置排序功能的默认值 ie 目前 页面加载时我有以下内容 但相反 我想要以下内容defaults当页面加载时 是否可以通过正确配置 Ransack Gem 来做到这一点 一如既往
  • 学说关系是否会影响应用程序性能?

    我正在与一个新团队一起开发 Symfony 项目 由于性能问题 他们决定尽可能停止使用 Doctrine 关系 例如 我必须存储我的 关系 的 id 而不是使用 ManyToOne 关系 但我想知道这是否是一个真正的问题 问题是 它改变了检
  • 在 PHP 中导入命名空间与包含文件

    我从 PHP 4 开始构建我的代码库 我使用过require once导入类 现在 在 PHP 5 3 中 我已经定义了名称空间并导入它们 我想更改我的源文件以使用导入 use声明 而不是使用require once 我不确定这是正确的决定
  • 如何使用自定义上传表单将文件上传到 WordPress?

    我不想使用 Wordpress 的内置媒体上传器 我的网站有一个表单 在前端 我需要允许任何人将图像上传到 wp content 中的我的上传文件夹 我找到了很多教程 但它们都告诉我如何使用 WordPress 上传器来做到这一点 我需要能
  • matlab:如何使用数组为绘图着色

    我有一组 3d 坐标 分为 3 个数组X Y Z 和温度T在每个点 我想将这些点绘制为点云 这样每个点都会根据其温度具有颜色 类似于您可以在中指定颜色的方式trisurf 我怎么做 您可以使用SCATTER3 http www mathwo
  • 如何判断 div 是否有高度限制?

    我想知道使用jquery div 是否有高度限制 例如 这个 div 被限制为 100px 无论内容的大小如何 div 的高度都将是 100px div style height 100px bla bla div 并且这个不受限制并且将占
  • Pyinstaller:警告:找不到库

    我正在尝试从使用 PyQt5 的代码创建一个可执行文件 我使用Python 3 5 3 64位 在Windows 10中开发 使用pip安装pyinstaller 3 2 1 并安装pywin32 Pyinstaller 运行但输出未找到库
  • 如何解决 Blazor Server 默认项目解决方案中的命名空间错误(Visual Studio 代码)

    我使用 vs code 创建了多个新的 BlazorServer 项目dotnet new blazorserver在多台电脑上 我总是收到此错误 The type or namespace name Shared does not exi
  • WPF 应用程序将数据表写入 Excel 的更有效方法?

    In my WPF应用程序 我有一个巨大的数据表 System Data DataTable 我需要写入 Excel 文档中的工作表 这是该函数的重点部分 for i lt dt Rows Count i for int colNum 0
  • 为arm64 iOS构建C库(GMP)

    我正在尝试为arm64 构建一个C 库 GMP 6 0 0 以在iOS 上使用 我正在使用下面的调用运行配置脚本 编译器是使用 xcrun find 找到的 configure CC Applications Xcode app Conte
  • Java 11之后wsimport在哪里

    我已经使用 wsimport 和其他 Metro 工具很多年了 但自从 Java 11 中删除了 Java EE 模块后 我找不到这些工具了 我在哪里可以找到wsimport可执行的 WSIMPORT 的可执行文件可以在主站点找到https
  • 如何以编程方式创建新的密钥库?

    我正在尝试以编程方式在 Java 中创建一个新的密钥库 以下代码 KeyStore keyStore KeyStore getInstance KeyStore getDefaultType keyStore setCertificateE
  • 如何在Python中找到两个字符串之间的最长交集?

    我正在尝试编写一个程序来找到两个字符串之间最长的交集 条件是 如果没有公共字符 程序将返回一个空链 如果有多个相同长度的公共字符子串 则应返回最大的一个 例如 对于 bbaacc 和 aabb 重复子串是 aa 和 bb 但 bb gt a
  • Mock 框架与 MS Fakes 框架

    对 NMock 等 Mock 框架与 VS 2011 Fakes 框架的差异有点困惑 通过MSDN 我了解到Fakes允许您像RhinoMock或NMock一样模拟您的依赖项 但是方法不同 Fakes生成代码来实现此功能 但Mocks框架不
  • 选定的文本背景颜色

    当我使用任何网站时 我看到选定的文本背景颜色显示蓝色或根据我们的操作系统主题 我可以更改此选定的文本背景颜色吗 您可以使用这种风格 这适用于除 IE 之外的所有主要浏览器
  • Python 3.3 无法导入 Crypt

    当我在命令行中输入 import Crypt 时 它会显示 gt gt gt import crypt Traceback most recent call last File
  • 如何编写正则表达式“行”包含字符串[重复]

    这个问题在这里已经有答案了 我有字符串 one line second line magic line foo third line 如何仅使用关键字将整行与 foo 匹配foo 所以 我可以匹配foo using foo g 但我不知道如
  • 如何在运行时获取测试环境

    我想检查代码是否正在运行go test 这样我就可以进行一些配置 有什么功能可以做到这一点吗 喜欢 运行时 IsBeingTested 只需指定您在 test 中运行测试init 例如 在 pkg go 中 package pkg var
  • 从 Chrome 94+ 与不支持 HTTPS 的 LAN 设备通过网络应用程序进行通信

    我们开发了一个 Web 应用程序 通过发送 POST 请求与连接到同一 LAN 的打印机进行通信 此类打印机有一个在端口 80 上打开的服务器 该服务器接受包含命令的 XML 无法从通过 HTTPS 加载的页面与网络设备进行通信 因此 我们
  • 调用 SaveChanges() 时排除更新属性

    似乎有两种方法可以使用 附加 方法来更新断开连接的实体框架实体 方法一是简单地将断开连接的实体的状态设置为已修改 myDbContext Dogs Attach dog myDbContext Entry dog State EntityS