views:

35

answers:

2

I have an application in mind which dicates database tables be append-only; that is, I can only insert data into the database but never update or delete it. I would like to use LINQ to SQL to build this.

Since tables are append-only but I still need to be able to "delete" data, my thought is that each table Foo needs to have a corresponding FooDeletion table. The FooDeletion table contains a foreign key which references a Foo that has been deleted. For example, the following tables describe the state "Foos 1, 2, and 3 exist, but Foo 2 and Foo 3 have been deleted".

Foo      FooDeletion
id       id  fooid
----    -------------
1        1   2
2        2   3
3

Although I could build an abstraction on top of the data access layer which (a) prevents direct access to LINQ to SQL entities and (b) manages deletions in this manner, one of my goals is to keep my data access layer as thin as possible, so I'd prefer to make the DataContext or entity classes do the work behind the scenes. So, I'd like to let callers use Table<Foo>.DeleteOnSubmit() like normal, and the DAL knows to add a row to FooDeletion instead of deleting a row from Foo.

I've read through "Implementing Business Logic" and "Customizing the Insert, Update, and Delete Behavior of Entity Classes", but I can't find a concrete way to implement what I want. I thought I could use the partial method DataContext.DeleteFoo() to instead call ExecuteDynamicInsert(FooDeletion), but according to this article, "If an inapplicable method is called (for example, ExecuteDynamicDelete for an object to be updated), the results are undefined".

Is this a fool's errand? Am I making this far harder on myself than I need to?

+2  A: 

You have more than one option - you can either:

a) Override SubmitChanges, take the change set (GetChangeSet()) and translate updates and deletes into inserts.

b) Use instead-of triggers db-side to change the updates/delete behavior.

c) Add a new Delete extension method to Table that implements the behavior you want.

d) ...or combine a+b+c as needed...

KristoferA - Huagati.com
(a) is the trick I needed. Inside my SubmitChanges, I'll enumerate the updates and deletions and make the appropriate translation, then call this.Refresh() or InsertOnSubmit() to cancel out the insertion. Thanks!
Stephen Jennings
Hrm... after playing around, I think (c) is the better option so I don't need to add the "fail on delete attempt" infrastructure to each class. No matter, you still got me the right answer.
Stephen Jennings
A: 

if you want a big-boy enterprise quality solution, you'd put it in the database - either b) from above or CRUD procedures <- my preference... triggers are evil.

If this is a small shop, not a lot of other developers or teams, or data of minimal value such that a second or third app trying to access the data isn't likely than stick with whatever floats your boat.

Stephanie Page