Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

Setting Default Values for LINQ Bound Data

3.53/5 (8 votes)
21 Feb 2008CPOL4 min read 4   119  
How to stop LINQ from trying to insert null data into your database
Article_src

Introduction

Being impressed with the new ORM behaviour exhibited by Microsoft's new LINQ technology, I decided to do a development spike before using it in my next project. Although LINQ is definitely the way to go, there would seem to be a few shortfalls that require a bit of working around. Here I write about a fairly nasty behavior where LINQ objects' properties are set with null values causing the database to reject updates and inserts on columns that won't allow null data.

Using the Code

I ran into a problem using the ASP.NET DetailsView control and an underlying LINQ DataSource. The issue: When I load an object using LINQ rather than using the default values for the properties derived from the database, the default value for each property is null. Being a good DBA, I never (without good reason) have nulls lying around my databases, so my tables always have default values assigned to each column. When the LINQ objects however are sent back to the database, the operation fails since the DB is rejecting the LINQ layer trying to insert that null data.

I think this is a bit of a flaw in the design. By default, LINQ objects should be initialized with properties mapping back to the default values used in the underlying data store.

Anyway, better to demonstrate with a simple example of this problem and then show a workaround …
I have a simple data table...

Image 2

SQL
CREATE TABLE [dbo].[Table1](
    [Col1] [int] IDENTITY(1,1) NOT NULL,
    [Col2] [nvarchar](50) NOT NULL CONSTRAINT [DF_Table1_Col2]  DEFAULT (''),
    [Col3] [int] NOT NULL CONSTRAINT [DF_Table1_col3]  DEFAULT ((0)),
    [Col4] [datetime] NOT NULL CONSTRAINT [DF_Table1_col4]  DEFAULT (getdate()),
 CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
    [Col1] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = _
    OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

... and a LINQ class sitting on the table:

Image 3

Next, I add a LinqDataSource to the project's default page (default.aspx) and set both a filtering parameter based on the underlying data's primary key and let the datasource know that I also want to be able to edit the data.

ASP.NET
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
            ContextTypeName="DataClassesDataContext" EnableUpdate="True"
            TableName="Table1s" Where="Col1 == @Col1">
<WhereParameters>
          <asp:QueryStringParameter Name="Col1" QueryStringField="Col1" Type="Int32" />
      </WhereParameters>
</asp:LinqDataSource>

As a UI for the data, I drag a DetailsView control onto the page and bind it to the LinqDataSource.

ASP.NET
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
        DataKeyNames="Col1" DataSourceID="LinqDataSource1" Height="50px" Width="125px">
        <Fields>
            <asp:BoundField DataField="Col1" HeaderText="Col1" InsertVisible="False"
                ReadOnly="True" SortExpression="Col1" />
            <asp:BoundField DataField="Col2" HeaderText="Col2" SortExpression="Col2" />
            <asp:BoundField DataField="Col3" HeaderText="Col3" SortExpression="Col3" />
            <asp:BoundField DataField="Col4" HeaderText="Col4" SortExpression="Col4" />
            <asp:CommandField ShowEditButton="True" />
        </Fields>
    </asp:DetailsView>

I manually add a single record to my data table so as to have some data to edit:

Image 4

Note that Col2 is empty, but by definition it should be an empty string.

SQL
[Col2] [nvarchar](50) NOT NULL CONSTRAINT [DF_Table1_Col2]  DEFAULT (''),

Let's try and edit the data for this single row (making sure to supply the query string parameter Col1=1)

Image 5

So, I leave Col2 empty and hit the update link.

plain
Cannot insert the value NULL into column 'Col2', table 'TestDB.dbo.Table1'; 
    column does not allow nulls. UPDATE fails.
The statement has been terminated.
Description: An unhandled exception occurred during the execution of the 
    current web request. Please review the stack trace for more information about 
    the error and where it originated in the code.

Exception Details: System.Data.SqlClient.SqlException: 
    Cannot insert the value NULL into column 'Col2', table 'TestDB.dbo.Table1'; 
    column does not allow nulls. UPDATE fails.
The statement has been terminated.

Source Error:
An unhandled exception was generated during the execution of the current web request. 
    Information regarding the origin and location of the exception can be identified 
    using the exception stack trace below.

Stack Trace:

[SqlException (0x80131904): Cannot insert the value NULL into column 'Col2', 
    table 'TestDB.dbo.Table1'; column does not allow nulls. UPDATE fails.
The statement has been terminated.]
   System.Data.SqlClient.SqlConnection.OnError_
        (SqlException exception, Boolean breakConnection) +925466
   System.Data.SqlClient.SqlInternalConnection.OnError_
        (SqlException exception, Boolean breakConnection) +800118
   System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning_
        (TdsParserStateObject stateObj) +186
   System.Data.SqlClient.TdsParser.Run_
        (RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, _
        BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) +1932
   System.Data.SqlClient.SqlCommand.FinishExecuteReader_
        (SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) +149
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds_
        (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, _
        Boolean async) +1005
   System.Data.SqlClient.SqlCommand.RunExecuteReader_
        (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, _
        String method, DbAsyncResult result) +132
   System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery_
        (DbAsyncResult result, String methodName, Boolean sendToPipe) +149
   System.Data.SqlClient.SqlCommand.ExecuteNonQuery() +135
   System.Data.Linq.SqlClient.SqlProvider.Execute_
        (Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, _
        Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, _
        Object lastResult) +229
   System.Data.Linq.SqlClient.SqlProvider.ExecuteAll_
        (Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, _
        Object[] userArguments, ICompiledSubQuery[] subQueries) +129
   System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute_
        (Expression query) +878
   System.Data.Linq.StandardChangeDirector.DynamicUpdate(TrackedObject item) +127
   System.Data.Linq.StandardChangeDirector.Update(TrackedObject item) +168
   System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) +433
   System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) +1155
   System.Data.Linq.DataContext.SubmitChanges() +82
   System.Web.UI.WebControls.LinqToSqlWrapper.SubmitChanges(DataContext dataContext) +9
   System.Web.UI.WebControls.LinqDataSourceView.UpdateDataObject_
    (Object dataContext, Object table, Object oldDataObject, Object newDataObject) +106
   System.Web.UI.WebControls.LinqDataSourceView.ExecuteUpdate_
    (IDictionary keys, IDictionary values, IDictionary oldValues) +326
   System.Web.UI.DataSourceView.Update_
        (IDictionary keys, IDictionary values, IDictionary oldValues, _
        DataSourceViewOperationCallback callback) +78
   System.Web.UI.WebControls.DetailsView.HandleUpdate_
        (String commandArg, Boolean causesValidation) +1152
   System.Web.UI.WebControls.DetailsView.HandleEvent_
        (EventArgs e, Boolean causesValidation, String validationGroup) +440
   System.Web.UI.WebControls.DetailsView.OnBubbleEvent(Object source, EventArgs e) +95
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.DetailsViewRow.OnBubbleEvent_
        (Object source, EventArgs e) +109
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +115
   System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +132
   System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler._
        RaisePostBackEvent(String eventArgument) +7
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, _
        String eventArgument) +11
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +177
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, _
        Boolean includeStagesAfterAsyncPoint) +1746

________________________________________
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; 
    ASP.NET Version:2.0.50727.1433

Annoying or what?
Firstly, this is not a new insert, so when the LINQ object loaded the data for the row, Col2 should have been set to the value obtained from the database in col2, which was an empty string. Second, if it was a new insert, then I want to use the defaults set in the table definition for each column, not null.

So, let's try a new insert. I modify both the DataSource and the DetailsView to support inserts as well as updates:

ASP.NET
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
            ContextTypeName="DataClassesDataContext" EnableInsert="True"
            EnableUpdate="True" TableName="Table1s" Where="Col1 == @Col1">
            <WhereParameters>
                <asp:QueryStringParameter Name="Col1" QueryStringField="Col1" 
                Type="Int32" />
            </WhereParameters>
        </asp:LinqDataSource>

   <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
            DataKeyNames="Col1" DataSourceID="LinqDataSource1" 
                Height="50px" Width="125px">
            <Fields>
                <asp:BoundField DataField="Col1" HeaderText="Col1" InsertVisible="False"
                    ReadOnly="True" SortExpression="Col1" />
                <asp:BoundField DataField="Col2" HeaderText="Col2" 
                        SortExpression="Col2" />
                <asp:BoundField DataField="Col3" HeaderText="Col3" 
                        SortExpression="Col3" />
                <asp:BoundField DataField="Col4" HeaderText="Col4" 
                        SortExpression="Col4" />
                <asp:CommandField ShowEditButton="True" ShowInsertButton="True" />
            </Fields>
        </asp:DetailsView>

Now I try a fresh insert leaving each of the columns on the DetailsView blank:

Image 6

And click the insert link:

plain
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
Description: An unhandled exception occurred during the execution of 
    the current web request. Please review the stack trace for more information 
    about the error and where it originated in the code.

Exception Details: System.Data.SqlTypes.SqlTypeException: SqlDateTime overflow. 
    Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

Source Error:
An unhandled exception was generated during the execution of the current web request. 
    Information regarding the origin and location of the exception can be identified 
    using the exception stack trace below.

Stack Trace:

[SqlTypeException: SqlDateTime overflow. 
    Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.]
   System.Data.SqlTypes.SqlDateTime.FromTimeSpan(TimeSpan value) +653497
   System.Data.SqlTypes.SqlDateTime.FromDateTime(DateTime value) +150
   System.Data.SqlTypes.SqlDateTime..ctor(DateTime value) +13
   System.Data.SqlClient.MetaType.FromDateTime(DateTime dateTime, Byte cb) +56
   System.Data.SqlClient.TdsParser.WriteValue_
        (Object value, MetaType type, Byte scale, Int32 actualLength, _
        Int32 encodingByteSize, Int32 offset, _
        TdsParserStateObject stateObj) +519
   System.Data.SqlClient.TdsParser.TdsExecuteRPC_
        (_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, _
        SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, _
        Boolean isCommandProc) +4163
   System.Data.SqlClient.SqlCommand.RunExecuteReaderTds_
        (CommandBehavior cmdBehavior, RunBehavior runBehavior, _
        Boolean returnStream, Boolean async) +1005
   System.Data.SqlClient.SqlCommand.RunExecuteReader_
        (CommandBehavior cmdBehavior, RunBehavior runBehavior, _
        Boolean returnStream, String method, DbAsyncResult result) +132
   System.Data.SqlClient.SqlCommand.RunExecuteReader_
        (CommandBehavior cmdBehavior, RunBehavior runBehavior, _
        Boolean returnStream, String method) +32
   System.Data.SqlClient.SqlCommand.ExecuteReader_
        (CommandBehavior behavior, String method) +122
   System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) +12
   System.Data.Common.DbCommand.ExecuteReader() +9
   System.Data.Linq.SqlClient.SqlProvider.Execute_
        (Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, _
        Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, _
        Object lastResult) +903
   System.Data.Linq.SqlClient.SqlProvider.ExecuteAll_
        (Expression query, QueryInfo[] queryInfos, IObjectReaderFactory factory, _
        Object[] userArguments, ICompiledSubQuery[] subQueries) +129
   System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute_
        (Expression query) +878
   System.Data.Linq.StandardChangeDirector.DynamicInsert(TrackedObject item) +261
   System.Data.Linq.StandardChangeDirector.Insert(TrackedObject item) +168
   System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) +250
   System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) +1155
   System.Data.Linq.DataContext.SubmitChanges() +82
   System.Web.UI.WebControls.LinqToSqlWrapper.SubmitChanges(DataContext dataContext) +9
   System.Web.UI.WebControls.LinqDataSourceView.InsertDataObject_
        (Object dataContext, Object table, Object newDataObject) +82
   System.Web.UI.WebControls.LinqDataSourceView.ExecuteInsert(IDictionary values) +267
   System.Web.UI.DataSourceView.Insert_
        (IDictionary values, DataSourceViewOperationCallback callback) +72
   System.Web.UI.WebControls.DetailsView.HandleInsert_
        (String commandArg, Boolean causesValidation) +390
   System.Web.UI.WebControls.DetailsView.HandleEvent_
        (EventArgs e, Boolean causesValidation, String validationGroup) +602
   System.Web.UI.WebControls.DetailsView.OnBubbleEvent(Object source, EventArgs e) +95
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.DetailsViewRow.OnBubbleEvent_
        (Object source, EventArgs e) +109
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +115
   System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +132
   System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler._
        RaisePostBackEvent(String eventArgument) +7
   System.Web.UI.Page.RaisePostBackEvent_
        (IPostBackEventHandler sourceControl, String eventArgument) +11
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +177
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, _
        Boolean includeStagesAfterAsyncPoint) +1746

________________________________________
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; 
    ASP.NET Version:2.0.50727.1433

Hmm, I thought I was setting that default value to GetDate() in the table definition.

So I'm thinking there must be some way I can tell my LINQ layer to let the DB handle the defaults and stop messing things up.

If I look in the LINQ designed code behind file, I can see LINQ attributes set above each property indexer relating to the underlying DB, for Col2 in this case:

SQL
[Column(Storage="_Col2", DbType="NVarChar(50) NOT NULL", CanBeNull=false)]
    public string Col2
    {
        get
        {
            return this._Col2;
        }
        set
        {
            if ((this._Col2 != value))
            {
                this.OnCol2Changing(value);
                this.SendPropertyChanging();
                this._Col2 = value;
                this.SendPropertyChanged("Col2");
                this.OnCol2Changed();
            }
        }
    }

So it knows that it can't be null, yet its default value for the property is null. Sorry, but that's not very clever. I had a look at other flags I could set that would maybe force LINQ to use the DB defaults. The intellisense gives me the following :

Image 7

IsDbGenerated looks like a pretty good guess, so I try that:

SQL
[Column(Storage="_Col2", DbType="NVarChar(50) NOT NULL", _
    CanBeNull=false, IsDbGenerated=true)]

I try editing my data again, but on update I get the following error:

plain
Value of member 'Col2' of an object of type 'Table1' changed.
A member that is computed or generated by the database cannot be changed.
Description: An unhandled exception occurred during the execution of the 
    current web request. Please review the stack trace for more information 
    about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: 
    Value of member 'Col2' of an object of type 'Table1' changed.
A member that is computed or generated by the database cannot be changed.

Source Error:
An unhandled exception was generated during the execution of the current web request. 
    Information regarding the origin and location of the exception can be identified 
    using the exception stack trace below.

Stack Trace:

[InvalidOperationException: Value of member 'Col2' of an object of type 'Table1' changed.
A member that is computed or generated by the database cannot be changed.]
   System.Data.Linq.ChangeProcessor.CheckForInvalidChanges(TrackedObject tracked) +291
   System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) +415
   System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) +1155
   System.Data.Linq.DataContext.SubmitChanges() +82
   System.Web.UI.WebControls.LinqToSqlWrapper.SubmitChanges(DataContext dataContext) +9
   System.Web.UI.WebControls.LinqDataSourceView.UpdateDataObject_
        (Object dataContext, Object table, Object oldDataObject, _
        Object newDataObject) +106
   System.Web.UI.WebControls.LinqDataSourceView.ExecuteUpdate_
        (IDictionary keys, IDictionary values, IDictionary oldValues) +326
   System.Web.UI.DataSourceView.Update(IDictionary keys, IDictionary values, _
        IDictionary oldValues, DataSourceViewOperationCallback callback) +78
   System.Web.UI.WebControls.DetailsView.HandleUpdate_
        (String commandArg, Boolean causesValidation) +1152
   System.Web.UI.WebControls.DetailsView.HandleEvent_
        (EventArgs e, Boolean causesValidation, String validationGroup) +440
   System.Web.UI.WebControls.DetailsView.OnBubbleEvent(Object source, EventArgs e) +95
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.DetailsViewRow.OnBubbleEvent_
        (Object source, EventArgs e) +109
   System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +35
   System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +115
   System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +132
   System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler._
        RaisePostBackEvent(String eventArgument) +7
   System.Web.UI.Page.RaisePostBackEvent_
        (IPostBackEventHandler sourceControl, String eventArgument) +11
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +177
   System.Web.UI.Page.ProcessRequestMain_
        (Boolean includeStagesBeforeAsyncPoint, _
        Boolean includeStagesAfterAsyncPoint) +1746

________________________________________
Version Information: Microsoft .NET Framework Version:2.0.50727.1433; 
    ASP.NET Version:2.0.50727.1433

Now, I am really beginning to get frustrated. I played with this for hours, and trawled the Web to try and find a solution that doesn't involve me writing code. No luck so far.

So here's my workaround:

What I definitely didn't want to do is write any code that is explicitly bound to any table definition because if the table changes it will definitely become a maintenance issue. I also didn't want to have to write partial methods to check on each of the LINQ properties for nulls as they are being set because that means more maintenance code. So, the best thing I could think of is to hook into the update event from the DetailsView control and make sure the LINQ object is properly initialized before trying to permeate it back to the database. I modified the LinqDataSource control to call a check method when the OnUpdating and OnInserting methods are fired, as below:

ASP.NET
<asp:LinqDataSource ID="LinqDataSource1" runat="server"
          ContextTypeName="DataClassesDataContext" EnableInsert="True"
          EnableUpdate="True" TableName="Table1s" Where="Col1 == _
              @Col1" OnUpdating="SetDefaultUpdateValues" _
              OnInserting="SetDefaultInsertValues">
          <WhereParameters>
              <asp:QueryStringParameter Name="Col1" QueryStringField="Col1" _
                      Type="Int32" />
          </WhereParameters>
      </asp:LinqDataSource>

The code behind is as follows:

C#
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Reflection;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    private void SetDefaults(object LinqObj)
    {
        // get the properties of the LINQ Object
        PropertyInfo[] props = LinqObj.GetType().GetProperties();

        // iterate through each property of the class
        foreach (PropertyInfo prop in props)
        {
            // attempt to discover any metadata relating to underlying data columns
            try
            {
                // get any column attributes created by the Linq designer
                object[] customAttributes = prop.GetCustomAttributes
                (typeof(System.Data.Linq.Mapping.ColumnAttribute), false);

                // if the property has an attribute letting us know that 
                // the underlying column data cannot be null
                if (((System.Data.Linq.Mapping.ColumnAttribute)
                (customAttributes[0])).DbType.ToLower().IndexOf("not null") != -1)
                {
                    // if the current property is null or Linq has set a date time 
                // to its default '01/01/0001 00:00:00'
                    if (prop.GetValue(LinqObj, null) == null || prop.GetValue(LinqObj, 
                    null).ToString() == (new DateTime(1, 1, 1, 0, 0, 0)).ToString())
                    {

                        // set the default values here : could re-query the database, 
                        // but would be expensive so just use defaults coded here
                        switch (prop.PropertyType.ToString())
                        {
                            // System.String / NVarchar
                            case "System.String":
                                prop.SetValue(LinqObj, String.Empty, null);
                                break;
                            case "System.Int32":
                            case "System.Int64":
                            case "System.Int16":
                                prop.SetValue(LinqObj, 0, null);
                                break;
                            case "System.DateTime":
                                prop.SetValue(LinqObj, DateTime.Now, null);
                                break;
                        }
                    }
                }
            }
            catch
            {
                // could do something here ...
            }
        }
    }

    // set LINQ objects default values for new insert
    protected void SetDefaultInsertValues(object sender, LinqDataSourceInsertEventArgs e)
    {
        SetDefaults(e.NewObject);
    }

    // set LINQ objects default values for update
    protected void SetDefaultUpdateValues(object sender, LinqDataSourceUpdateEventArgs e)
    {
        SetDefaults(e.NewObject);
    }
}

Points of Interest

The shortfall of the above method is that the default values set in the code aren't derived from the database. This could be corrected, but it would be expensive. It's a shame the LINQ designer doesn't add the default column value as metadata during the creation of the classes. I assume Microsoft will find a fix for this soon.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)