ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – EntityFramework未识别手动进行的实体更改

2019-06-08 23:01:58  阅读:179  来源: 互联网

标签:c entity-framework entity-framework-6


我正在手动更改实体,然后我试图验证我的DbContext中是否有任何与我的更改匹配的实体.我所期待的“答案”是“真实的”,但它是“假的”.
由于我的代码非常复杂并且有很多规则,我创建了一个简单的例子来尝试解释这个问题:

var propertyValues = new Dictionary<string, object>()
{
    {"MyProperty1", "My value"},
    {"MyProperty2", 10}
};

var entityId = 13;
var entityType = typeof(MyEntity);

// Applies the changes
this.ApplyChanges(db, entityType, entityId, propertyValues);


// This is "false"
var hasEntityWithValue = db.MyEntity.Any(p => p.Id == entityId && p.MyProperty1 != null);

// The "myEntity" is null
var myEntity = db.MyEntity.FirstOrDefault(p => p.Id == entityId && p.MyProperty1 != null);

// Gets the entity only by Id
myEntity = db.MyEntity.FirstOrDefault(p => p.Id == entityId);

// And when I compare the "MyProperty1" it's "true". Why?????
hasEntityWithValue = myEntity.MyProperty1 != null;

“ApplyChanges”方法:

private void ApplyChanges(DbContext db, Type entityType, int entityId, 
Dictionary<string, object> propertyValues)
{
    var entity = db.Set(entityType).Find(entityId);
    foreach (var propertyValue in propertyValues)
    {
        var propertyInfo = entityType.GetProperty(propertyValue.Key);

        // Sets the value
        propertyInfo.SetValue(entity, propertyValue.Value);
    }

    db.ChangeTracker.DetectChanges();
}

我相信这种情况正在发生,因为当我查询实体时,我在数据库中查询它们而不是EntityFramework“缓存”.

但是,当我通过使用IQueryable扩展方法(例如“Any”和“FirstOrDefault”方法)查询DbContext中的实体时,有没有办法强制EntityFramework识别更改?

解决方法:

让我们看看前两个陈述:

var entityId = 13;
...

// This is "false"
var hasEntityWithValue = db.MyEntity.Any(p => p.Id == entityId && p.MyProperty1 != null);

// The "myEntity" is null
var myEntity = db.MyEntity.FirstOrDefault(p => p.Id == entityId && p.MyProperty1 != null);

这两个都向数据库发送相同的查询:

SELECT * FROM MyEntities WHERE ID = 13 AND MyProperty1 IS NOT NULL

这不返回数据库中的记录,因为数据库还没有新数据 – 没有记录保存在数据库中的ID为13,其中MyProperty1不为NULL.这是因为你还没有调用db.SaveChanges().第一个语句将该SQL语句的结果转换为false值,而第二个语句将其转换为null值.

继续下一个声明:

// Gets the entity only by Id
myEntity = db.MyEntity.FirstOrDefault(p => p.Id == entityId);

这会向数据库发送一个查询,如下所示:

SELECT * FROM MyEntities WHERE ID = 13

数据库确实有一个ID为13的MyEntitiy,它将MyEntity返回给EF.但是,在EF将MyEntity返回给您之前,EF会检查其缓存中是否有ID为13的MyEntity.它有一个ID为13的缓存MyEntity,因此它会发送缓存的MyEntity.缓存的MyEntity恰好是您在调用自定义ApplyChanges方法时更新的.

// And when I compare the "MyProperty1" it's "true". Why?????
hasEntityWithValue = myEntity.MyProperty1 != null;

这是正确的原因是因为返回给您的实体是EF缓存中的实体.

当您使用EF进行查询时,它会将查询发送到数据库,如果从数据库返回记录,EF将检查其缓存以查看具有相同密钥的记录是否在缓存中.如果它们已存在于缓存中,则将返回缓存的记录以代替在数据库中找到的记录,即使缓存的记录与数据库记录不同也是如此. (有关如何绕过此缓存的更多信息,请参阅http://codethug.com/2016/02/19/Entity-Framework-Cache-Busting/)

缓存检查在查询运行时完成.所以你可以打这个电话,你会看到你的更新数据:

var data = db.MyEntity
    .Where(p => p.Id == entityId)
    .ToList()
    .Where(p => p.MyProperty1 != null);

第一个Where函数由数据库处理.第二个在运行C#代码的任何地方都在内存中处理. ToList调用强制将目前构建的查询发送到数据库,并在完成任何更多过滤或排序之前运行.

您也可以使用此事务,但正如您所提到的,这将在事务持续期间锁定资源.假设您正在使用EF6,您可以这样做:

using (var transaction = db.Database.BeginTransaction()) 
{
    // Applies the changes
    this.ApplyChanges(db, entityType, entityId, propertyValues);

    db.SaveChanges();    

    // Should be true
    var hasEntityWithValue = db.MyEntity.Any(p => p.Id == entityId && p.MyProperty1!=null);

    // At this point, queries to the database will see the updates you made 
    // in the ApplyChanges method
    var isValid = ValidateSave();

    if (isValid)
    {
        // Assuming no more changes were made since you called db.SaveChanges()
        transaction .Commit(); 
    }
    else
    {
        transaction .Rollback(); 
    }
}

标签:c,entity-framework,entity-framework-6
来源: https://codeday.me/bug/20190608/1201222.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有