Optimizing Repository’s SubmitChanges Method

2019-01-15 12:13发布

问题:

I have following repository. I have a mapping between LINQ 2 SQL generated classes and domain objects using a factory.

The following code will work; but I am seeing two potential issues

1) It is using a SELECT query before update statement.

2) It need to update all the columns (not only the changed column). This is because we don’t know what all columns got changed in the domain object.

How to overcome these shortcomings?

Note: There can be scenarios (like triggers) which gets executed based on specific column update. So I cannot update a column unnecessarily.

REFERENCE:

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

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

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


}

回答1:

If I understand your question, you are being passed an entity that you need to save to the database without knowing what the original values were, or which of the columns have actually changed.

If that is the case, then you have four options

  1. You need to go back to the database to see the original values ie perform the select, as you code is doing. This allows you to set all your entity values and Linq2Sql will take care of which columns are actually changed. So if none of your columns are actually changed, then no update statement is triggered.

  2. You need to avoid the select and just update the columns. You already know how to do (but for others see this question and answer). Since you don't know which columns have changed you have no option but set them all. This will produce an update statement even if no columns are actually changed and this can trigger any database triggers. Apart from disabling the triggers, about the only thing you can do here is make sure that the triggers are written to check the old and new columns values to avoid any further unnecessary updates.

  3. You need to change your requirements/program so that you require both old and new entities values, so you can determine which columns have changed without going back to the database.

  4. Don't use LINQ for your updates. LINQ stands for Language Integrated QUERY and it is (IMHO) brilliant at query, but I always looked on the updating/deleting features as an extra bonus, but not something which it was designed for. Also, if timing/performance is critical, then there is no way that LINQ will match properly hand-crafted SQL.



回答2:

This isn't really a DDD question; from what I can tell you are asking:

Use linq to generate direct update without select

Where the accepted answer was no its not possible, but theres a higher voted answer that suggests you can attach an object to your context to initiate the change tracking of the data context.

Your second point about disabling triggers has been answered here and here. But as others have commented do you really need the triggers? Should you not be controlling these updates in code?

In general I think you're looking at premature optimization. You're using an ORM and as part of that you're trusting in L2S to make the database plumbing decisions for you. But remember where appropriate you can use stored procedures execute specific your SQL.