【问题标题】:Optimizing Repository’s SubmitChanges Method优化 Repository 的 SubmitChanges 方法
【发布时间】:2012-06-29 13:34:13
【问题描述】:

我有以下存储库。我使用工厂在 LINQ 2 SQL 生成的类和域对象之间建立了映射。

以下代码将起作用;但我发现了两个潜在问题

1) 在更新语句之前使用 SELECT 查询。

2) 它需要更新所有列(不仅是更改的列)。这是因为我们不知道域对象中的所有列都发生了哪些变化。

如何克服这些缺点?

注意:可能存在基于特定列更新执行的场景(如触发器)。所以我不能不必要地更新列。

参考

  1. LINQ to SQL: Updating without Refresh when “UpdateCheck = Never”

  2. http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=113917

代码

namespace RepositoryLayer
{
public interface ILijosBankRepository
{      
    void SubmitChangesForEntity();
}

public class LijosSimpleBankRepository : ILijosBankRepository
{

    private IBankAccountFactory bankFactory = new MySimpleBankAccountFactory();
    public System.Data.Linq.DataContext Context
    {
        get;
        set;
    }


    public virtual void SubmitChangesForEntity(DomainEntitiesForBank.IBankAccount iBankAcc)
    {
        //Does not get help from automated change tracking (due to mapping)

        //Selecting the required entity
        DBML_Project.BankAccount tableEntity = Context.GetTable<DBML_Project.BankAccount>().SingleOrDefault(p => p.BankAccountID == iBankAcc.BankAccountID);

        if (tableEntity != null)
        {
            //Setting all the values to updates (except primary key)
            tableEntity.Status = iBankAcc.AccountStatus;

            //Type Checking
            if (iBankAcc is DomainEntitiesForBank.FixedBankAccount)
            {
                tableEntity.AccountType = "Fixed";
            }

            if (iBankAcc is DomainEntitiesForBank.SavingsBankAccount)
            {
                tableEntity.AccountType = "Savings";
            }

            Context.SubmitChanges();
        }
    }
}

}

namespace DomainEntitiesForBank
{

public interface IBankAccount
{
    int BankAccountID { get; set; }
    double Balance { get; set; }
    string AccountStatus { get; set; }
    void FreezeAccount();

}

public class FixedBankAccount : IBankAccount
{

    public int BankAccountID { get; set; }
    public string AccountStatus { get; set; }
    public double Balance { get; set; }

    public void FreezeAccount()
    {
        AccountStatus = "Frozen";
    }
}


}

【问题讨论】:

  • "需要更新所有列"。这对性能的影响到底是什么?你测量过这个吗?
  • @Steven 这是我的假设。毕竟,从逻辑上讲,这是不必要的努力。从 SQL 的角度来看,可能并非如此。此外,可能存在基于列更新执行的场景(如触发器)。所以我不能不必要地更新列。 sqlteam.com/forums/topic.asp?TOPIC_ID=113917
  • 除非你“继承”了数据库设计,否则我认为你真的必须重新考虑触发器的这种使用。如果您只是因为记录更改而需要触发,请在表中使用时间戳并让更新触发器对此做出响应。

标签: c# .net design-patterns linq-to-sql domain-driven-design


【解决方案1】:

如果我理解您的问题,您将被传递一个实体,您需要将其保存到数据库中,而不知道原始值是什么,或者哪些列实际发生了变化。

如果是这样,那么你有四个选择

  1. 您需要返回数据库查看原始值,即执行选择,就像您的代码所做的那样。这允许您设置所有实体值,Linq2Sql 将负责实际更改哪些列。因此,如果您的所有列都没有实际更改,则不会触发更新语句。

  2. 您需要避免选择并只更新列。您已经知道该怎么做(但对于其他人,请参阅 this question and answer)。由于您不知道哪些列已更改,因此您别无选择,只能将它们全部设置。即使没有实际更改任何列,这也会产生一条更新语句,并且这可以触发任何数据库触发器。除了禁用触发器之外,您在这里唯一能做的就是确保编写触发器以检查旧列和新列的值,以避免进一步不必要的更新。

  3. 您需要更改您的要求/程序,以便同时需要新旧实体值,这样您就可以确定哪些列已更改,而无需返回数据库。

  4. 不要使用 LINQ 进行更新。 LINQ 代表 Language Integrated QUERY,它在查询方面非常出色(恕我直言),但我总是将更新/删除功能视为额外的奖励,但不是它的设计目的。此外,如果时间/性能很关键,那么 LINQ 将无法正确匹配手工制作的 SQL。

【讨论】:

  • 谢谢。关于选项 #2 的问题。如果我将生成的实体直接用作域类(不使用手动编写的域类进行映射),我可以只更新所需的列而无需选择。这将满足问题中的两个要求。您认为这种方法有什么缺点吗?
【解决方案2】:

这不是一个真正的 DDD 问题;据我所知,你在问:

Use linq to generate direct update without select

接受的答案是不可能,但有更高投票的答案表明您可以附加一个对象到您的上下文中以启动对数据上下文。

您关于禁用触发器的第二点已得到答复herehere。但正如其他人所评论的那样,你真的需要触发器吗?您不应该在代码中控制这些更新吗?

总的来说,我认为您正在考虑过早优化。您正在使用 ORM,作为其中的一部分,您信任 L2S 为您做出数据库管道决策。但请记住,您可以在适当的情况下使用存储过程来执行特定的 SQL。

【讨论】:

    猜你喜欢
    • 2016-03-26
    • 2012-05-07
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多