0

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


}
Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418
  • "It need to update all the column". What exactly is the performance hit of this? Have you measured this? – Steven Jun 29 '12 at 13:44
  • @Steven It was my assumption. After all, it is an unwanted effort -logically. May not be true from SQL perspective. Also, there can be scenarios (like triggers) which gets executed based on column update. So I cannot update a column unnecessarily. http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=113917 – LCJ Jun 29 '12 at 13:58
  • Unless you "inherited" the database design, I think you really have to reconsider this use of triggers. If you need to trigger just because the record changes, use a timestamp in the table and have your update triggers respond to that. – Pleun Jun 29 '12 at 16:49

2 Answers2

1

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.

Community
  • 1
  • 1
Chris Moutray
  • 18,029
  • 7
  • 45
  • 66
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.

Community
  • 1
  • 1
sgmoore
  • 15,694
  • 5
  • 43
  • 67
  • Thanks. Question regarding option #2. If I was using the generated entities directly as domain classes (without mapping with manually written domain classes), I could have updated the required columns only without a select. This will meet both the requirements in the question. Do you see any shortcomings with that approach? – LCJ Jul 02 '12 at 06:25