草庐IT

c# - 跟踪 Entity Framework 中与行为的多对多关系的变化

coder 2023-07-12 原文

我目前正在尝试使用 Entity Framework 的 ChangeTracker 进行审计。我正在覆盖我的 DbContext 中的 SaveChanges() 方法,并为已添加、修改或删除的实体创建日志。这是 FWIW 的代码:

public override int SaveChanges()
{
    var validStates = new EntityState[] { EntityState.Added, EntityState.Modified, EntityState.Deleted };
    var entities = ChangeTracker.Entries().Where(x => x.Entity is BaseEntity && validStates.Contains(x.State));
    var entriesToAudit = new Dictionary<object, EntityState>();
    foreach (var entity in entities)
    {
        entriesToAudit.Add(entity.Entity, entity.State);
    }
    //Save entries first so the IDs of new records will be populated
    var result = base.SaveChanges();
    createAuditLogs(entriesToAudit, entityRelationshipsToAudit, changeUserId);
    return result;
}

这对“普通”实体非常有用。然而,对于简单的多对多关系,我必须扩展此实现以包括“独立关联”,如 this 中所述。很棒的 SO 答案,它通过 ObjectContext 访问更改,如下所示:

private static IEnumerable<EntityRelationship> GetRelationships(this DbContext context, EntityState relationshipState, Func<ObjectStateEntry, int, object> getValue)
{
    context.ChangeTracker.DetectChanges();
    var objectContext = ((IObjectContextAdapter)context).ObjectContext;

    return objectContext
            .ObjectStateManager
            .GetObjectStateEntries(relationshipState)
            .Where(e => e.IsRelationship)
            .Select(
                e => new EntityRelationship(
                    e.EntitySet.Name,
                    objectContext.GetObjectByKey((EntityKey)getValue(e, 0)),
                    objectContext.GetObjectByKey((EntityKey)getValue(e, 1))));
}

一旦实现,这也很有效,但仅适用于使用联结表的多对多关系。通过这种方式,我指的是关系不是由类/实体表示的情况,而只是一个包含两列的数据库表 - 每个外键一列。

但是,在我的数据模型中存在某些多对多关系,其中关系具有“行为”(属性)。在此示例中,ProgramGroup 是具有 Pin 属性的多对多关系:

public class Program
{
    public int ProgramId { get; set; }
    public List<ProgramGroup> ProgramGroups { get; set; }
}

public class Group
{
    public int GroupId { get; set; }
    public IList<ProgramGroup> ProgramGroups { get; set; }
}

public class ProgramGroup
{
    public int ProgramGroupId { get; set; }
    public int ProgramId { get; set; }
    public int GroupId { get; set; }
    public string Pin { get; set; }
}

在这种情况下,我在“正常”DbContext ChangeTracker 和 ObjectContext 关系方法中都没有看到 ProgramGroup 发生变化(例如,如果 Pin 发生变化)。但是,当我逐步执行代码时,我可以看到更改发生在 ObjectContext 的 StateEntries 中,但它的条目具有 IsRelationship=false,这当然会导致 .Where(e = > e.IsRelationship) 条件。

我的问题是,为什么多对多关系与行为没有出现在正常的 DbContext ChangeTracker 中,因为它由实际的类/实体表示,为什么它没有标记为 ObjectContext StateEntries 中的关系?此外,访问这些类型的更改的最佳做法是什么?

提前致谢。

编辑: 针对@FrancescCastells 的评论,即可能未明确定义 ProgramGroup 的配置是问题的原因,我添加了以下配置:

public class ProgramGroupConfiguration : EntityTypeConfiguration<ProgramGroup>
{
    public ProgramGroupConfiguration()
    {
        ToTable("ProgramGroups");
        HasKey(p => p.ProgramGroupId);

        Property(p => p.ProgramGroupId).IsRequired();
        Property(p => p.ProgramId).IsRequired();
        Property(p => p.GroupId).IsRequired();
        Property(p => p.Pin).HasMaxLength(50).IsRequired();
    }

这是我的其他配置:

public class ProgramConfiguration : EntityTypeConfiguration<Program>
{
    public ProgramConfiguration()
    {
        ToTable("Programs");
        HasKey(p => p.ProgramId);
        Property(p => p.ProgramId).IsRequired();
        HasMany(p => p.ProgramGroups).WithRequired(p => p.Program).HasForeignKey(p => p.ProgramId);
    }
}

public class GroupConfiguration : EntityTypeConfiguration<Group>
{
    public GroupConfiguration()
    {
        ToTable("Groups");
        HasKey(p => p.GroupId);
        Property(p => p.GroupId).IsRequired();
        HasMany(p => p.ProgramGroups).WithRequired(p => p.Group).HasForeignKey(p => p.GroupId);
    }

当这些实现时,EF 仍然不会在 ChangeTracker 中显示修改后的 ProgramGroup

最佳答案

虽然在实体关系建模理论中提到了“与属性的关系”的概念,但就 Entity Framework 而言,您的 ProgramGroup 类是一个实体。您可能在第一个代码片段中使用 x.Entity is BaseEntity 检查无意中将其过滤掉。

关于c# - 跟踪 Entity Framework 中与行为的多对多关系的变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33611135/

有关c# - 跟踪 Entity Framework 中与行为的多对多关系的变化的更多相关文章

  1. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  4. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  5. ruby-on-rails - 启用 Rack::Deflater 时 ETag 发生变化 - 2

    在启用Rack::Deflater来gzip我的响应主体时偶然发现了一些奇怪的东西。也许我遗漏了一些东西,但启用此功能后,响应被压缩,但是资源的ETag在每个请求上都会发生变化。这会强制应用程序每次都响应,而不是发送304。这在没有启用Rack::Deflater的情况下有效,我已经验证页面源没有改变。我正在运行一个使用thin作为Web服务器的Rails应用程序。Gemfile.lockhttps://gist.github.com/2510816有没有什么方法可以让我从Rack中间件获得更多的输出,这样我就可以看到发生了什么?提前致谢。 最佳答案

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  8. ruby - Ruby gsub 替换中的行为不一致? - 2

    两个gsub产生不同的结果。谁能解释一下为什么?代码也可在https://gist.github.com/franklsf95/6c0f8938f28706b5644d获得.ver=9999str="\tCFBundleDevelopmentRegion\n\ten\n\tCFBundleVersion\n\t0.1.190\n\tAppID\n\t000000000000000"putsstr.gsub/(CFBundleVersion\n\t.*\.).*()/,"#{$1}#{ver}#{$2}"puts'--------'putsstr.gsub/(CFBundleVersio

  9. ruby-on-rails - Ruby 中意外的大小写行为 - 2

    我在一段非常简单的代码(如我所想)中得到了一个错误的值:org=4caseorgwhenorg=4val='H'endputsval=>nil请不要生气,我希望我错过了一些非常明显的东西,但我真的想不通。谢谢。 最佳答案 这是典型的Ruby错误。case有两种被调用的方法,一种是你传递一个东西作为分支的基础,另一种是你不传递的东西。如果您确实在case中指定了一个表达式语句然后评估所有其他条件并与===进行比较.在这种情况下org评估为false和org===false显然不是真的。所有其他情况也是如此,它们要么是真的,要么是假的。

  10. ruby - 使对象的行为类似于 ruby​​ 中并行分配的数组 - 2

    假设您在Ruby中执行此操作:ar=[1,2]x,y=ar然后,x==1和y==2。是否有一种方法可以在我自己的类中定义,从而产生相同的效果?例如rb=AllYourCode.newx,y=rb到目前为止,对于这样的赋值,我所能做的就是使x==rb和y=nil。Python有这样一个特性:>>>classFoo:...def__iter__(self):...returniter([1,2])...>>>x,y=Foo()>>>x1>>>y2 最佳答案 是的。定义#to_ary。这将使您的对象被视为要分配的数组。irb>o=Obje

随机推荐