【问题标题】:Get DbContext from within Entity从实体中获取 DbContext
【发布时间】:2013-09-08 20:17:27
【问题描述】:

在我的项目中,我通常没有单独的数据访问层,但出于性能原因,我喜欢向我的实体添加一些原始 SQL 方法。

所以我的一个实体类中有一个 MassUpdateSomethingAndPersist()。要进行大规模更新,我需要从实体内部调用dbContext.Database.ExecuteSqlCommand。但我当然需要先引用 DbContext。

问题

是否可以从实体中获取 DbContext?对此使用反射对我来说不是问题,因为无论如何这些都是相对繁重的操作。

【问题讨论】:

    标签: .net entity-framework


    【解决方案1】:

    我认为您正在尝试执行的操作表明存在 OO 设计缺陷。更新数据库不应该是实体类的责任。这是DBContext 的责任。

    所以

    1. 不,这是不可能的,而且
    2. 想要这样做,表明存在设计缺陷(可能)

    如果您想执行自定义 SQL,您应该在上下文中从调用者执行它,而不是从实体本身内部执行。

    可以在此处找到示例:DBContext Native SQL Queries

    【讨论】:

    • 您是否有一些好的资源可以解释为什么这是一个如此糟糕的做法(对于中型项目)——只要通过方法可以清楚地知道它会持续到数据库中吗?仅仅与实体合作,假装它背后没有(缓慢的)数据库操作已被证明不适合我的项目。
    • 嗯,这真的只是很好的 OO 实践。关键词:SRP,关注点分离,依赖倒置原则。阅读 SOLID 原则(例如:codeproject.com/Articles/60845/…)。您的建议至少会违反依赖倒置和单一职责原则。
    • 是的,我知道 SOLID,但我喜欢看一些实际的例子。就像我之前说的 - 假装实体背后没有(缓慢的)数据库操作已证明不适用于我的项目。添加在某些非常特殊的情况下执行原始 SQL 的(命名良好的)方法对我尚未来说不是问题。对于不同的问题,也许是一个很好的话题:)
    • 嗯,当然你可以添加自定义 SQL,但你应该将它添加到 DBContext 而不是实体本身。实体应该完全不知道持久性机制。它们应该是带有属性的纯 .NET 类,并且持久性应该由 DbContext 处理。
    • Ps:感谢您竭尽全力回答我的问题!也许您可以删除第 1 点,因为这似乎是错误的 - 请参阅接受的答案。
    【解决方案2】:

    有可能:

    ((IObjectContextAdapter)dbContext).ObjectContext.ObjectMaterialized += (sender, e) => 
    {
        (e.Entity as IEntityWithDbContext).DbContext = dbContext;
    }
    
    public interface IEntityWithDbContext
    {
        public DbContext DbContext { get; set; }
    }
    
    public partial class User : IEntityWithDbContext
    {
        public IEntityWithDbContext.DbContext DbContext { get; set; }
    }
    

    但这仍然是一个设计缺陷......

    根据您的描述,您应该可以轻松地将 MassUpdateSomethingAndPersist() 设为 DbContext 的方法(即 MassUpdateSomethingAndPersist(something))。

    【讨论】:

    • 问题是因为我(显然?)使用相对较大的数据集工作,所以我有很多这些方法。在我看来,将它们全部添加到 DbContext really 违反了“单一职责”原则。为这些“大规模更新”为每个实体创建一个单独的类对我来说似乎是很多额外的开销,而我并没有真正看到它解决任何直接问题(只要很清楚该方法也将它持久化到数据库中) )。
    【解决方案3】:

    在实体框架中,您应该遵循实体的领域驱动设计 (DDD) 概念,即它始终是persistence ignorant。如果您按照您的要求打破这种模式,那么您可能会发现进行正确的单元测试非常困难。

    对象在数据库中修改其自己的表示的模式称为the Active Record Pattern,实体框架不鼓励这样做。如果您想使用 Active Record 模式,请查看为其设计的框架 - 例如 Castle ActiveRecord

    【讨论】:

    • 如果您只更改实体上的两个字段,则单元测试相当容易。问题是,在我的现实应用程序中,有时我需要同时更新数百个属性。在没有 SQL 的情况下这样做是不可能的,因此代码的用户无论如何都无法“无知”地工作。我的大部分代码仍然对持久性一无所知,但有时我真的需要一个 MassUpdateAndPersist()。
    • 不过,Castle ActiveRecord 看起来很有趣,所以如果对我有进一步帮助,我可以看看。
    • 我看不出字段数与它有什么关系。您只需根据需要更新尽可能多的实体,然后传递要保存的更新实体。一个大的保存将比数百个小保存更有效。
    • 另外,我并不是在提倡 Castle Active Record,我只是说它是为该模式设计的框架。就个人而言,我会选择完全远离 Active Record 模式。 Here is a decent article 为什么它会给你带来麻烦。
    • 抱歉不清楚——我的意思当然是数百个不同实体的属性。如 UPDATE Match SET Points = 10 WHERE Winner = 'Lolcat'。
    猜你喜欢
    • 1970-01-01
    • 2017-06-13
    • 2012-04-24
    • 1970-01-01
    • 2017-06-15
    • 2012-11-11
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多