July 2010 - Blake Niemyjski

  • How-to: Using a Stored Procedure extended property to preserve custom logic in the CSLA generated code.

    In the previous article on how to use the partial methods in the CodeSmith CSLA templates to preserve custom code mostly focused on the code side of things. For those of you who might be using Stored Procedures might be wondering... How do I accomplish preserving my custom stored procedure logic? Don't worry, CodeSmith already though of this and didn't leave you out in the dark! The CSLA templates by default will not automatically execute the generated stored procedures but it can! To do this you need to set the AutoExecuteStoredProcedures property to True. Now, when your database related metadata changes so will your stored procedures.

    This is a great feature until you need to implement custom logic into your stored procedure. By default we will generate logic that will prevent a stored procedure from being overwritten if you have AutoExecuteStoredProcedures turned to true or you try to drop the stored procedure. Here is the example that we are going to be modifying that will result in the same exact output as our previous sample.

    SET NUMERIC_ROUNDABORT OFF
    GO
    SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON
    GO
    IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
    GO
    CREATE TABLE #tmpErrors (Error int)
    GO
    SET XACT_ABORT ON
    GO
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    GO
    BEGIN TRANSACTION
    GO
    PRINT N'Dropping CSLA_Calendar_Select'
    GO
    IF EXISTS(SELECT 1 FROM fn_listextendedproperty (NULL, 'SCHEMA', 'dbo', 'PROCEDURE', 'CSLA_Calendar_Select', default, default) WHERE name = 'CustomProcedure' and value = '1')
    BEGIN
        RAISERROR ('The procedure CSLA_Calendar_Select has an Extended Property "CustomProcedure" which means is has been customized. Please review and remove the property if you wish to drop the procedure.',16,1)
        INSERT INTO #tmpErrors (Error) SELECT 1
    END
    GO
    
    IF OBJECT_ID(N'CSLA_Calendar_Select') IS NOT NULL
    	DROP PROCEDURE CSLA_Calendar_Select
    
    GO
    IF @@ERROR!=0 AND @@TRANCOUNT>0 ROLLBACK TRANSACTION
    GO
    
    IF @@TRANCOUNT=0 BEGIN INSERT INTO #tmpErrors (Error) SELECT 1 BEGIN TRANSACTION END
    GO
    
    IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
    GO
    
    IF @@TRANCOUNT>0 BEGIN
    PRINT 'The stored procedure drop has succeeded'
    COMMIT TRANSACTION
    END
    ELSE PRINT 'The stored procedure drop has failed'
    GO
    
    DROP TABLE #tmpErrors
    GO
    
    --region [dbo].[CSLA_Calendar_Select]
    
    ------------------------------------------------------------------------------------------------------------------------
    -- Generated By:   Blake Niemyjski using CodeSmith: v5.2.3, CSLA Templates: v3.0.0.1888, CSLA Framework: v3.8.4
    -- Procedure Name: [dbo].[CSLA_Calendar_Select]
    ------------------------------------------------------------------------------------------------------------------------
    
    SET NUMERIC_ROUNDABORT OFF
    GO
    SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS ON
    GO
    IF EXISTS (SELECT * FROM tempdb..sysobjects WHERE id=OBJECT_ID('tempdb..#tmpErrors')) DROP TABLE #tmpErrors
    GO
    CREATE TABLE #tmpErrors (Error int)
    GO
    SET XACT_ABORT ON
    GO
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    GO
    BEGIN TRANSACTION
    GO
    
    PRINT N'Creating [dbo].[CSLA_Calendar_Select]'
    GO
    
    IF EXISTS(SELECT 1 FROM fn_listextendedproperty (NULL, 'SCHEMA', 'dbo', 'PROCEDURE', 'CSLA_Calendar_Select', default, default) WHERE name = 'CustomProcedure' and value = '1')
        BEGIN
            RAISERROR ('The procedure [dbo].[CSLA_Calendar_Select] has an Extended Property "CustomProcedure" which means is has been customized. Please review and remove the property if you wish to create the stored procedure.',16,1)
            INSERT INTO #tmpErrors (Error) SELECT 1
        END
    GO
    
    CREATE PROCEDURE [dbo].[CSLA_Calendar_Select]
    	@p_ID nvarchar(50) = NULL,
    	@p_CalendarName nvarchar(50) = NULL,
    	@p_Name nvarchar(50) = NULL,
    	@p_EventStart datetime = NULL,
    	@p_EventEnd datetime = NULL,
    	@p_Resource nvarchar(150) = NULL
    AS
    
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    
    SELECT
    	[ID],
    	[CalendarName],
    	[Name],
    	[EventStart],
    	[EventEnd],
    	[Resource]
    FROM
        [dbo].[Calendar]
    WHERE
    	([ID] = @p_ID OR @p_ID IS NULL)
    	AND ([CalendarName] = @p_CalendarName OR @p_CalendarName IS NULL)
    	AND ([Name] = @p_Name OR @p_Name IS NULL)
    	AND ([EventStart] = @p_EventStart OR @p_EventStart IS NULL)
    	AND ([EventEnd] = @p_EventEnd OR @p_EventEnd IS NULL)
    	AND ([Resource] = @p_Resource OR @p_Resource IS NULL)
    
    GO
    IF @@ERROR!=0 AND @@TRANCOUNT>0 ROLLBACK TRANSACTION
    GO
    
    IF @@TRANCOUNT=0 BEGIN INSERT INTO #tmpErrors (Error) SELECT 1 BEGIN TRANSACTION END
    GO
    
    IF EXISTS (SELECT * FROM #tmpErrors) ROLLBACK TRANSACTION
    GO
    IF @@TRANCOUNT>0 BEGIN
    PRINT 'Stored procedure creation succeeded.'
    COMMIT TRANSACTION
    END
    ELSE PRINT 'Stored procedure creation failed.'
    GO
    DROP TABLE #tmpErrors
    GO
    
    --endregion

    Let's open up SQL Management Studio and run the script above. Once you run the query above, you can see that the table was dropped and recreated.

    Dropping CSLA_Calendar_Select

    The stored procedure drop has succeeded

    Creating [dbo].[CSLA_Calendar_Select]

    Stored procedure creation succeeded.

    Now that you can see that the stored procedure is being overwritten, let's modify the stored procedure to return the same results as our previous example.

    ALTER PROCEDURE [dbo].[CSLA_Calendar_Select]
    	@p_ID nvarchar(50) = NULL,
    	@p_CalendarName nvarchar(50) = NULL,
    	@p_Name nvarchar(50) = NULL,
    	@p_EventStart datetime = NULL,
    	@p_EventEnd datetime = NULL,
    	@p_Resource nvarchar(150) = NULL
    AS
    
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    
    SELECT
    	[ID],
    	[CalendarName],
    	[Name],
    	[EventStart],
    	[EventEnd],
    	[Resource]
    FROM
        [dbo].[Calendar]
    WHERE
    	([ID] = @p_ID OR @p_ID IS NULL)
    	AND ([CalendarName] = @p_CalendarName OR @p_CalendarName IS NULL)
    	AND ([Name] = @p_Name OR @p_Name IS NULL)
    	AND ([EventStart] = @p_EventStart OR @p_EventStart IS NULL)
    	AND ([EventEnd] = @p_EventEnd OR @p_EventEnd IS NULL)
    	AND ([Resource] = @p_Resource OR @p_Resource IS NULL)
    	AND [EventStart] >= CONVERT(varchar,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0),101)

    Since you modified the stored procedure, you want to mark it as a custom Stored Procedure. If you choose not to do this, then you will need to modify this stored procedure any time you wish to regenerate or drop and recreate this stored procedure. This can be done by right clicking on the stored procedure, selecting properties and then selecting the Extended Properties node. You will want to create a new extended property with a name of CustomProcedure and a value of 1. The following SQL Script will also create the extended property.

    EXEC sys.sp_addextendedproperty @name=N'CustomProcedure', @value=N'1' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'PROCEDURE',@level1name=N'CSLA_Calendar_Select'
    GO

    Now when you execute the SQL script to drop and create the stored procedure it will error out and preserve your changes!

    Dropping CSLA_Calendar_Select

    Msg 50000, Level 16, State 1, Line 3

    The procedure CSLA_Calendar_Select has an Extended Property "CustomProcedure" which means is has been customized. Please review and remove the property if you wish to drop the procedure.


    (1 row(s) affected)

    The stored procedure drop has failed

    Creating [dbo].[CSLA_Calendar_Select]

    Msg 50000, Level 16, State 1, Line 4

    The procedure [dbo].[CSLA_Calendar_Select] has an Extended Property "CustomProcedure" which means is has been customized. Please review and remove the property if you wish to create the stored procedure.


    (1 row(s) affected)

    Msg 2714, Level 16, State 3, Procedure CSLA_Calendar_Select, Line 13

    There is already an object named 'CSLA_Calendar_Select' in the database.


    (1 row(s) affected)

    Stored procedure creation failed.

     

  • How-to: Using the CSLA partial methods to preserve custom code and promote active regeneration.

    One of the best features of code generation is the reality of being able to actively generate you code while preserving custom changes. This allows you to implement custom logic while constantly making changes to your metadata and getting the latest template changes. CodeSmith has worked hard on making this happen in both the PLINQO and CSLA Templates. The CSLA templates offer many partial method overrides to make your life easier. It is recommended that you place any partial methods that you implement in the non-generated partial class; this is always the ClassName.cs or ClassName.vb source code file.

    A list of partial methods can be found at the bottom of the every generated partial class. Here is an example of the generated partial methods.

    C#

    #region DataPortal partial methods
    
    partial void OnCreating(ref bool cancel);
    partial void OnCreated();
    partial void OnFetching(CalendarCriteria criteria, ref bool cancel);
    partial void OnFetched();
    partial void OnMapping(SafeDataReader reader, ref bool cancel);
    partial void OnMapped();
    partial void OnUpdating(ref bool cancel);
    partial void OnUpdated();
    partial void OnAddNewCore(ref Calendar item, ref bool cancel);
    
    #endregion

    Visual Basic

    #Region "DataPortal partial methods"
        
    Partial Private Sub OnCreating(ByRef cancel As Boolean)
    End Sub
    Partial Private Sub OnCreated()
    End Sub
    Partial Private Sub OnFetching(ByVal criteria As CalendarCriteria, ByRef cancel As Boolean)
    End Sub
    Partial Private Sub OnFetched()
    End Sub
    Partial Private Sub OnMapping(ByVal reader As SafeDataReader, ByRef cancel As Boolean)
    End Sub
    Partial Private Sub OnMapped()
    End Sub
    Partial Private Sub OnUpdating(ByRef cancel As Boolean)
    End Sub
    Partial Private Sub OnUpdated()
    End Sub
    Partial Private Sub OnAddNewCore(ByVal item As Calendar, ByRef cancel As Boolean)
    End Sub
        
    #End Region

    In this example we will take an EditableRootList called CalendarList, whose purpose is to hold a list of Calendar business objects. The default generated code will select all calendar entries with a specific criterion. The code below is the code that is generated in the CalendarList.DataAccess partial class:

    C#

    private void DataPortal_Fetch(CalendarCriteria criteria)
    {
        bool cancel = false;
        OnFetching(criteria, ref cancel);
        if (cancel) return;
    
        RaiseListChangedEvents = false;
    
        // Fetch Child objects.
        string commandText = string.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0}", ADOHelper.BuildWhereStatement(criteria.StateBag));
        using (SqlConnection connection = new SqlConnection(ADOHelper.ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(commandText, connection))
            {
                command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag));
    
                using(var reader = new SafeDataReader(command.ExecuteReader()))
                {
                    if(reader.Read())
                    {
                        do
                        {
                            this.Add(new Calendar(reader));
                        } while(reader.Read());
                    }
                }
            }
        }
    
        RaiseListChangedEvents = true;
    
        OnFetched();
    }

    Visual Basic

     

    Private Shadows Sub DataPortal_Fetch(ByVal criteria As CalendarCriteria)
        Dim cancel As Boolean = False
        OnFetching(criteria, cancel)
        If (cancel) Then
            Return
        End If
    
        RaiseListChangedEvents = False
    
        ' Fetch Child objects.
        Dim commandText As String = String.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0}", ADOHelper.BuildWhereStatement(criteria.StateBag))
        Using connection As New SqlConnection(ADOHelper.ConnectionString)
            connection.Open()
            Using command As New SqlCommand(commandText, connection)
                command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag))
                Using reader As SafeDataReader = New SafeDataReader(command.ExecuteReader())
                    If reader.Read() Then
                        Do
                            Me.Add(New Calendar(reader))
                        Loop While reader.Read()
                    End If
                End Using
            End Using
        End Using
    
        RaiseListChangedEvents = True
    
        OnFetched()
    End Sub

     

    As you can see that this isn't optimal because we only want to select all Calendar entries from the first of the current month. In the real word we would only want to select maybe a month of two or data... This can easily be done by overriding the partial method and modifying the sql statement. We will now go to the partial non generated class (CalendarList.cs or CalendarList.vb):

    C#

    #region Custom Data Access
    
    partial void OnFetching(CalendarCriteria criteria, ref bool cancel)
    {
        RaiseListChangedEvents = false;
    
        // Fetch Child objects.
        string commandText = string.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0} AND [EventStart] >= CONVERT(varchar,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0),101)", ADOHelper.BuildWhereStatement(criteria.StateBag));
        using (SqlConnection connection = new SqlConnection(ADOHelper.ConnectionString))
        {
            connection.Open();
            using (SqlCommand command = new SqlCommand(commandText, connection))
            {
                command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag));
    
                using (var reader = new SafeDataReader(command.ExecuteReader()))
                {
                    if (reader.Read())
                    {
                        do
                        {
                            this.Add(new Calendar(reader));
                        } while (reader.Read());
                    }
                }
            }
        }
    
        RaiseListChangedEvents = true;
    
        // Cancel the existing Dal method.
        cancel = true;
    }
    
    #endregion

    Visual Basic

    #Region "Custom Data Access"
    Private Sub OnFetching(ByVal criteria As CategoryCriteria, ByRef cancel As Boolean)
        RaiseListChangedEvents = False
    
        ' Fetch Child objects.
        Dim commandText As String = String.Format("SELECT [ID], [CalendarName], [Name], [EventStart], [EventEnd], [Resource] FROM [dbo].[Calendar] {0} AND [EventStart] >= CONVERT(varchar,DATEADD(MONTH,DATEDIFF(MONTH,0,GETDATE()),0),101)", ADOHelper.BuildWhereStatement(criteria.StateBag))
        Using connection As New SqlConnection(ADOHelper.ConnectionString)
            connection.Open()
            Using command As New SqlCommand(commandText, connection)
                command.Parameters.AddRange(ADOHelper.SqlParameters(criteria.StateBag))
                Using reader As SafeDataReader = New SafeDataReader(command.ExecuteReader())
                    If reader.Read() Then
                        Do
                            Me.Add(New Calendar(reader))
                        Loop While reader.Read()
                    End If
                End Using
            End Using
        End Using
    
        RaiseListChangedEvents = True
    
        'Cancel the existing Dal method.
        cancel = True
    End Sub
    #End Region

    As you can see all we needed to do was implement the OnFetching partial method and override the sql query that was then sent to the database server. You can do anything you want in this partial method. The last thing to do is set the reference cancel variable to true if you wish to have everything after the partial method call ignored. If you set this to false then the existing generated code will also run. In this case, we want to cancel out. A scenario where you would want to return false, is if you wanted to do some processing before accessing the database.

    If you come across something that you wish had a partial method, please log it on the CodeSmith template issue tracker.

  • Breaking CSLA 4.0 property changes when using private backing fields.

    I came across this bug last night, which was occurring right as CSLA4 was released. It had to deal with the CodeSmith CSLA templates when you set UseMemberVariables to true. The error is quite obscure and not very intuitive as the signs of a bug are only found when you check to see if your business object IsValid. The scenario in this case is when you set a required managed property, the rules never fully evaluate the set value. A bunch of other side effects could occur as well. Here is the error you could receive:

    CategoryId required
      Expected: True
      But was:  False

    Here is the code that was causing the error:

    C#

    protected override void AddBusinessRules()
    {
        BusinessRules.AddRule(new Csla.Rules.CommonRules.Required(_categoryIdProperty));
    }
    
    private static readonly PropertyInfo< System.String > _categoryIdProperty = RegisterProperty< System.String >(p => p.CategoryId, string.Empty);
    private System.String _categoryId = _categoryIdProperty.DefaultValue;
    public System.String CategoryId
    {
        get { return GetProperty(_categoryIdProperty, _categoryId); }
        set { SetProperty(_categoryIdProperty, ref _categoryId, value); }
    }
    
    [Test]
    private void CreateCategory(string categoryID)
    {
        Category category = Category.NewCategory();
        category.CategoryId = categoryID;
        Assert.IsTrue(category.IsValid, category.BrokenRulesCollection.ToString());
    
        category = category.Save();
    
        Assert.IsTrue(category.CategoryId == categoryID);
    }

    Visual Basic

    Protected Overrides Sub AddBusinessRules()
        BusinessRules.AddRule(New Csla.Rules.CommonRules.Required(_categoryIdProperty))
    End Sub
    
    Private Shared ReadOnly _categoryIdProperty As PropertyInfo(Of System.String) = RegisterProperty(Of System.String)(Function(p As Category) p.CategoryId, String.Empty)
    Private _categoryId As System.String = _categoryIdProperty.DefaultValue
    Public Property CategoryId() As System.String
        Get 
            Return GetProperty(_categoryIdProperty, _categoryId) 
        End Get
        Set (value As System.String)
            SetProperty(_categoryIdProperty, _categoryId, value)
        End Set
    End Property
    
    <Test()> _
    Private Sub CreateCategory(ByVal categoryID As String)
        Dim category As Category = PetShop.Tests.ParameterizedSQL.Category.NewCategory()
        category.CategoryId = categoryID
    
        Assert.IsTrue(category.IsValid, category.BrokenRulesCollection.ToString())
        category = category.Save()
    
        Assert.IsTrue(category.CategoryId = categoryID)
    End Sub

    As you can see the code looks and works fine in CSLA 3.8 but it isn't the case in 4.0. Once I tracked down what was causing the error, I saw that there wasn't any checks in CSLA4 to see if the property had the RelationshipTypes.PrivateField overload when you are calling the GetProperty or SetProperty methods with a backing field. The long term fix when using private member backing fields is to set the RelationshipTypes to RelationshipTypes.PrivateField.

    C#

    private static readonly PropertyInfo< System.String > _categoryIdProperty = RegisterProperty< System.String >(p => p.CategoryId, string.Empty, RelationshipTypes.PrivateField);
    private System.String _categoryId = _categoryIdProperty.DefaultValue;
    public System.String CategoryId
    {
        get { return GetProperty(_categoryIdProperty, _categoryId); }
        set { SetProperty(_categoryIdProperty, ref _categoryId, value); }
    }

    Visual Basic

    Private Shared ReadOnly _categoryIdProperty As PropertyInfo(Of System.String) = RegisterProperty(Of System.String)(Function(p As Category) p.CategoryId, String.Empty, RelationshipTypes.PrivateField)
    Private _categoryId As System.String = _categoryIdProperty.DefaultValue
    Public Property CategoryId() As System.String
        Get 
            Return GetProperty(_categoryIdProperty, _categoryId) 
        End Get
        Set (value As System.String)
            SetProperty(_categoryIdProperty, _categoryId, value)
        End Set
    End Property

    This has been fixed in a nightly build of the CodeSmith CSLA Templates and will be in version 3.0.1 of the CodeSmith CSLA Templates. The CSLA team will also be releasing version 4.0.1 of CSLA sometime soon. If you don't have this overload set in CSLA 4.0.1 then you will receive the following exception:

    Properties with private backing fields must be marked as RelationshipTypes.PrivateField

    If you are using the CodeSmith CSLA templates, remember to update to the latest templates and regenerate. If you are not, well you should be using the CodeSmith CSLA Templates as it is about to save you a ton of time adding the RelationshipTypes.PrivateField overload to all of your properties!

  • How to upgrade a Community Server website thats running 2.1, 2007 or 2008 site to Community Server 2008 or Telligent Community 5.5

    I have done a few of these upgrades for a few big sites like Bink.nu and Sober.com. Here is the safest way without a ton of headaches. Please contact me if you need help, I'm willing to do the upgrade for people as well... Please do SQL backups after every step!

    Database Instructions

    1. Upgrade from Community Server 2.1 to 2007.0
    2. Create a SQL backup.
    3. Run SQL Compare against a fresh database of cs2007 to the upgraded database and make sure everything transferred correctly.
    4. If there were changes, create a SQL backup.
    5. Run the upgrade from 2007.0 to the last service pack release of 2007. (I think it was SP3).
    6. Create a SQL backup.
    7. Upgrade from CS 2007 SP3 to CS 2008.
    8. Create a SQL backup.
    9. Run SQL Compare against a freshly created CS 2008 database against the upgrade database to ensure everything is correct.
    10. If there were changes, create a SQL backup.
    11. Upgrade to CS 2008.5 using the upgrade utility.
    12. Create a SQL backup.
    13. Upgrade to latest service pack.
    14. Run SQL Compare against a freshly created CS 2008.5 SP3 database against the upgrade database to ensure everything is correct.
    15. --------------- Continue here if you are going to the latest version of TC 5.5-------
    16. Upgrade to TC 5.5.
    17. Run SQL Compare against a freshly created CS TC 5.5 database against the upgrade database to ensure everything is correct.

    Site File upgrade.

    1. The important thing here is that you need to do the upgrade process in order and make notes of changes. When doing this for a live database, do a run through of everything and make notes of things changing or failing and get them resolved a head of time.
    2. For the upgrade to 2007, read the readme and make sure you copy the storage files into the correct spot.
      1. I would extract the complete 2007 site files and copy the photo storage folders and everything to the correct spot.
    3. To upgrade to 2008, you need to run the upgrade utility.
      1. I would extract the complete 2008 site files and read the read me. I would copy the site files to the correct spots as they were.
      2. Once you are running this tool (somewhat buggy), I would make sure that you check the log file and copy over the file storage in the utilities folder to the file storage folder on the destination site.
      3. Then I would copy the old file storage folders to the same locations in the new site... I've had cases where they are hard linked and then you get missing files. I would only ever delete these folders after completely upgraded and you have them backed up...
    4. To upgrade to 2008.5, I'm pretty sure it's using the upgrade utility again, go back to step 3.
    5. To upgrade to TC 5.5, you need to extract the clean website (to a new directory).
      1. Next, copy over only the file storage folder (leave the old file storage folders \photos\, \blogs\, \forums\ for now (just to be safe).

    Final Steps.

    1. Copy the files from steps 4 or 5 to the web server.
    2. Replace permissions on all upgraded files.
    3. You will need to make sure that all of your custom scripts are updated accordingly.
    4. Make sure all images and links are working.

  • How-to: Preserve column names in generated PLINQO entities.

     

    There may come a time where you need to rename a column in your generated entity for whatever reason. The following tip and trick article will show you how to quickly accomplish this.

    Let's assume you have a generated property for the column AccountId and it is defined like this:

    [System.CodeDom.Compiler.GeneratedCode("CodeSmith", "5.0.0.0")]
    private int _accountId = default(int);
    
    /// <summary>
    /// Gets the AccountId column value.
    /// </summary>
    [System.Data.Linq.Mapping.Column(Name = "AccountId", Storage = "_accountId", DbType = "int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false)]
    [System.Runtime.Serialization.DataMember(Order = 1)]
    [System.CodeDom.Compiler.GeneratedCode("CodeSmith", "5.0.0.0")]
    public int AccountId
    {
        get { return _accountId; }
        set
        {
            if (_accountId != value)
            {
                OnAccountIdChanging(value);
                SendPropertyChanging("AccountId");
                _accountId = value;
                SendPropertyChanged("AccountId");
                OnAccountIdChanged();
            }
        }
    }

    If you take a look at the DBML file, it will look like this:

    <Type Name="Account">
      <Column Name="AccountId" Storage="_accountId" Type="System.Int32" DbType="int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
    </Type>

    Say you want to change the name of the property and have it preserved across generation. You will need to open the generated DBML file with the designer and change the name. I recommend always opening up the DBML file with an Xml Text editor (right click on the dbml file and select open with) and update the definition like this. Please note that opening the DBML file in the class designer will cause custom DBML data to be lost!

     

    <Type Name="Account">
      <Column Name="AccountId" Member="Id" Storage="_id" Type="System.Int32" DbType="int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
    </Type>

    Notice that an Member Attribute was added and the Storage Attribute value was changed. These are the two attributes that you will need to modify in order to rename properties in the DBML file. If you regenerate and take a look at the generated partial class. You will see that the AccountID property was dropped and the Id Property was created:

     

    [System.CodeDom.Compiler.GeneratedCode("CodeSmith", "5.0.0.0")]
    private int _id = default(int);
    
    /// <summary>
    /// Gets the AccountId column value.
    /// </summary>
    [System.Data.Linq.Mapping.Column(Name = "AccountId", Storage = "_id", DbType = "int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false)]
    [System.Runtime.Serialization.DataMember(Order = 12)]
    [System.CodeDom.Compiler.GeneratedCode("CodeSmith", "5.0.0.0")]
    public int Id
    {
        get { return _id; }
        set
        {
            if (_id != value)
            {
                OnIdChanging(value);
                SendPropertyChanging("Id");
                _id = value;
                SendPropertyChanged("Id");
                OnIdChanged();
            }
        }
    }

     

  • Upgrading from CSLA 3.8.4 to CSLA 4.0 using the CodeSmith CSLA templates version 3.0.0.

     

    We recently released a new major version of the CSLA templates that add support for many new features including Visual Studio 2010, CSLA 4.0 and Silverlight 4.0 support. They can be downloaded here. When upgrading to the templates and you are going from CSLA 3.8 to the latest CSLA 3.8.4 templates, there really aren’t any changes you need to make other than updating your CodeSmith Project File template location to point to the new version of the templates.  The easiest way to do this is to open up Visual Studio and double click on the CodeSmith Project File and do a replace all on that file path as this will update all file paths in all CodeSmith Project Files.

    If you are upgrading from CSLA 3.8 to CSLA 4.0 then additional work is required. The first step is to convert your solution to Visual Studio 2010 and set all the projects to use the .NET Framework v4.0.

    Secondly, you will need to do is go into your CodeSmith Project Settings and change the FrameworkVersion Property from v35 to v40. If you are planning on using Silverlight it is best to set the IncludeSilverlightSupport property to true to save you additional merging steps.

    The next step is to regenerate the files; you will notice that there are some build errors.  This is due to the entity partial classes are not regenerated and there are some required changes for Rules or for Silverlight. If you didn’t make any changes to the non-generated partial classes (E.G. Account.cs or Account.vb), then it is safe to delete the entire class and regenerate.

    Tip: if your Location property is set to a full path, I recommend setting it to “.\” without the quotes.

    If this is not the case then I recommend backing up your solution if it is not under source control (highly recommended). I would copy the CodeSmith Project File to a new folder and use a program like beyond compare to merge the partial classes together.  Since you have already regenerated, the generated partial classes will be in sync with CSLA 4.0 and won’t require a diff so your favorite diffing program will tell you that there is no work needing to be done.

    As you can see from the diff above, you will need to diff the changes. I’d recommend putting all of your Custom Code in region blocks as this makes merging much easier. This shouldn’t ever need to be merged again unless CSLA introduces some breaking changes.

     

windowscoding.com;
Copyright © 2008 Windows Coding
Microsoft and Microsoft logo's are trademarks of Microsoft Corporation.