优化存储库的SubmitChanges方法

时间:2012-06-29 13:34:14

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

我有以下资源库。我使用工厂在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

  3. CODE

    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";
        }
    }
    
    
    }
    

2 个答案:

答案 0 :(得分:1)

这不是真正的DDD问题;从我可以告诉你的问题:

Use linq to generate direct update without select

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

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

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

答案 1 :(得分:1)

如果我理解了您的问题,那么您将被传递给需要保存到数据库的实体,而不知道原始值是什么,或者哪些列实际已更改。

如果是这种情况,那么你有四个选择

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

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

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

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