Problem with generate from XML.

Problem with generate from XML.

Old forum URL: forums.lhotka.net/forums/t/1788.aspx


wjcomeaux posted on Friday, November 17, 2006

Any idea why the below is generating an
"Error Rendering BuildingEC: Unique Column(s) is required" error? It's very similar to the XML in the MySample.xml file for the Project object.
 
Thanks, Will
 
- <Object Access="public" Type="EditableChild" Name="BuildingEC" NameSpace="">
  <PropertyAuthorization>Write</PropertyAuthorization>
  <TransactionalType>TransactionScope</TransactionalType>
  <AuthorizationRules>false</AuthorizationRules>
- <Properties>
- <Property Name="ID" Type="int" DbColumnName="ID" Default="" IsPrimaryKey="true" IsIdentity="true">
- <ValidationRules>
  <Required />
  </ValidationRules>
  </Property>
- <Property Name="Name" Type="string" DbColumnName="Name" Default="">
- <ValidationRules>
  <StringMaxLength>50</StringMaxLength>
  </ValidationRules>
  </Property>
  <Property Name="CompanyID" Type="int" DbColumnName="CompanyID" Default="" />
  <Property Name="CompanyEC" Type="EditableChild" DbColumnName="CompanyEC" Default="" IsChild="true" />
  </Properties>
- <DbCommands DbName="PTracker">
  <FetchCommand Type="StoredProcedure">gen_BuildingEC_Fetch</FetchCommand>
  <InsertCommand>gen_BuildingEC_Insert</InsertCommand>
  <UpdateCommand>gen_BuildingEC_Update</UpdateCommand>
  <DeleteCommand>gen_BuildingEC_Delete</DeleteCommand>
  </DbCommands>
  </Object>

JoOfMetL replied on Monday, November 20, 2006

At which time does occur the error?

wjcomeaux replied on Monday, November 20, 2006

As soon as I run the template that generates business objects from the XML file. The error gets output to the window on the template.

Will

wjcomeaux replied on Monday, November 20, 2006

The error occurs at this point in the TemplateBase.cs file.

if (_uniqueProperties.Count == 0 && !IsCollection)
                    throw new Exception("Unique Column(s) is required.");

AFAIK the _uniqueProperties property gets assigned when the XML for property contains an attribute of IsPrimaryKey="true"

As you can see, I have this attribute

<Property Name="ID" Type="int" IsPrimaryKey="true" IsIdentity="true" DbColumnName="ID" Description="" Default="" DataType="Int32" NativeType="Int32" SystemType="Int32">

The more I play with the templates the more it seems like the order of the attributes in a tag play a very large role in the generation, or possibly the addition of attributes the generator doesn't expect. Instead of just skipping them, the new attributes cause the generator not to function.

Just a guess. This is why I've requested an XSD for the XML the generator expects. If one is available.

Thanks,

Will

rasupit replied on Tuesday, November 21, 2006

I have no problem generating your data.  However, there are some invalid properties and invalid tag therefore the generated code may not generate correctly.  You should always validate against CslaProject.xsd, see mysample.xml on how it's done.

=== output =====
using System;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Csla.Validation;

[Serializable()]
public class BuildingEC : Csla.BusinessBase<BuildingEC>
{
    #region Business Properties and Methods

    //declare members
    private int _id = 0;
    private string _name = string.Empty;
    private int _companyID = 0;
    private EditableChild _companyEC;

    [System.ComponentModel.DataObjectField(true, true)]
    public int ID
    {
        get
        {
            return _id;
        }
    }

    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            CanWriteProperty("Name", true);
            if (value == null) value = string.Empty;
            if (!_name.Equals(value))
            {
                _name = value;
                PropertyHasChanged("Name");
            }
        }
    }

    public int CompanyID
    {
        get
        {
            return _companyID;
        }
        set
        {
            CanWriteProperty("CompanyID", true);
            if (!_companyID.Equals(value))
            {
                _companyID = value;
                PropertyHasChanged("CompanyID");
            }
        }
    }

    public EditableChild CompanyEC
    {
        get
        {
            return _companyEC;
        }
        set
        {
            CanWriteProperty("CompanyEC", true);
            if (!_companyEC.Equals(value))
            {
                _companyEC = value;
                PropertyHasChanged("CompanyEC");
            }
        }
    }
 
    protected override object GetIdValue()
    {
        return _id;
    }

    #endregion //Business Properties and Methods

    #region Validation Rules
    private void AddCustomRules()
    {
        //add custom/non-generated rules here...
    }

    private void AddCommonRules()
    {
        //
        // Name
        //
        ValidationRules.AddRule(CommonRules.StringMaxLength, new CommonRules.MaxLengthRuleArgs("Name", 50));
    }

    protected override void AddBusinessRules()
    {
        AddCommonRules();
        AddCustomRules();
    }
    #endregion //Validation Rules

    #region Factory Methods
    private static int _newID = -1;

    internal static BuildingEC NewBuildingEC()
    {
        return new BuildingEC();
    }

    internal static BuildingEC GetBuildingEC(SafeDataReader dr)
    {
        return new BuildingEC(dr);
    }

    private BuildingEC()
    {
        _id = _newID--;

        ValidationRules.CheckRules();
        MarkAsChild();
    }

    private BuildingEC(SafeDataReader dr)
    {
        MarkAsChild();
        Fetch(dr);
    }
    #endregion //Factory Methods

    #region Data Access

    #region Data Access - Fetch
    private void Fetch(SafeDataReader dr)
    {
        FetchObject(dr);
        MarkOld();
        ValidationRules.CheckRules();

        //load child object(s)
        FetchChildren(dr);
    }

    private void FetchObject(SafeDataReader dr)
    {
        _id = dr.GetInt32("ID");
        _name = dr.GetString("Name");
        _companyID = dr.GetInt32("CompanyID");
        _companyEC = (EditableChild)dr["CompanyEC"];
    }

    private void FetchChildren(SafeDataReader dr)
    {
    }
    #endregion //Data Access - Fetch

    #region Data Access - Insert
    internal void Insert(SqlConnection cn)
    {
        if (!IsDirty) return;

        ExecuteInsert(cn);
        MarkOld();

        //update child object(s)
        UpdateChildren(cn);
    }

    private void ExecuteInsert(SqlConnection cn)
    {
        using (SqlCommand cm = cn.CreateCommand())
        {
            cm.CommandType = CommandType.StoredProcedure;
            cm.CommandText = "gen_BuildingEC_Insert";

            AddInsertParameters(cm);

            cm.ExecuteNonQuery();

            _id = (int)cm.Parameters["@NewID"].Value;
        }//using
    }

    private void AddInsertParameters(SqlCommand cm)
    {
        cm.Parameters.AddWithValue("@Name", _name);
        cm.Parameters.AddWithValue("@CompanyID", _companyID);
        cm.Parameters.AddWithValue("@CompanyEC", _companyEC);
        cm.Parameters.AddWithValue("@NewID", _id);
        cm.Parameters["@NewID"].Direction = ParameterDirection.Output;
    }
    #endregion //Data Access - Insert

    #region Data Access - Update
    internal void Update(SqlConnection cn)
    {
        if (!IsDirty) return;

        if (base.IsDirty)
        {
            ExecuteUpdate(cn);
            MarkOld();
        }

        //update child object(s)
        UpdateChildren(cn);
    }

    private void ExecuteUpdate(SqlConnection cn)
    {
        using (SqlCommand cm = cn.CreateCommand())
        {
            cm.CommandType = CommandType.StoredProcedure;
            cm.CommandText = "gen_BuildingEC_Update";

            AddUpdateParameters(cm);

            cm.ExecuteNonQuery();

        }//using
    }

    private void AddUpdateParameters(SqlCommand cm)
    {
        cm.Parameters.AddWithValue("@ID", _id);
        cm.Parameters.AddWithValue("@Name", _name);
        cm.Parameters.AddWithValue("@CompanyID", _companyID);
        cm.Parameters.AddWithValue("@CompanyEC", _companyEC);
    }

    private void UpdateChildren(SqlConnection cn)
    {
    }
    #endregion //Data Access - Update

    #region Data Access - Delete
    internal void DeleteSelf(SqlConnection cn)
    {
        if (!IsDirty) return;
        if (IsNew) return;

        ExecuteDelete(cn);
        MarkNew();
    }

    private void ExecuteDelete(SqlConnection cn)
    {
        using (SqlCommand cm = cn.CreateCommand())
        {
            cm.CommandType = CommandType.StoredProcedure;
            cm.CommandText = "gen_BuildingEC_Delete";

            cm.Parameters.AddWithValue("@ID", this._id);

            cm.ExecuteNonQuery();
        }//using
    }
    #endregion //Data Access - Delete
    #endregion //Data Access
}

wjcomeaux replied on Tuesday, November 21, 2006

Hey rasupit

Thanks for the heads up on the XSD. I am now generating valid XML to create code against. However, I have now also identified a true issue.

The XSD will allow the creation of empty <ValidationRules/> nodes. This however, causes the generator to throw that "Unique Column(s)" error. If I remove those blank nodes then I generate fine.

The XML at the end of this post validates fine against that XSD using XMLSpy2007.

So, now the dilema is should I write my XML Generator check if I need a validation before including the tag or should the template that generates the C# be altered to ignore the empty validatin tags? I'd prefer the latter approach since the former approach requires me to build a string for the validationRules then after the rules are processed check if my string is not equal to "<ValidatinRules></ValidationRules>" If not then emit the XML.

I think it would be more correct to have the code generator template simply ignore an empty ValidationRules block.

Thanks, Will

Here is my XML

<?xml version="1.0" encoding="UTF-8"?>

<CslaProject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="C:\CODEGE~1\CSharp\CslaProject.xsd">

<ProjectName>MyApp.Library</ProjectName>

<GenerationMethod>SplitPartial</GenerationMethod>

<Objects>

<Object Access="public" Type="EditableRoot" Name="BuildingER" Namespace="MyCSLA">

<TransactionalType>TransactionScope</TransactionalType>

<PropertyAuthorization>Write</PropertyAuthorization>

<AuthorizationRules>false</AuthorizationRules>

<Properties>

<Property Access="private" Name="ID" Type="int" DbColumnName="ID" IsPrimaryKey="true" IsIdentity="true">

<ValidationRules/>

</Property>

<Property Access="private" Name="Name" Type="string" DbColumnName="Name">

<ValidationRules/>

</Property>

<Property Access="private" Name="CompanyID" Type="int" DbColumnName="CompanyID">

<ValidationRules/>

</Property>

</Properties>

<DbCommands DbName="PTracker">

<FetchCommand Type="StoredProcedure">gen_BuildingER_Fetch</FetchCommand>

<InsertCommand>gen_BuildingER_Insert</InsertCommand>

<UpdateCommand>gen_BuildingER_Update</UpdateCommand>

<DeleteCommand>gen_BuildingER_Delete</DeleteCommand>

</DbCommands>

</Object>

</Objects>

</CslaProject>

wjcomeaux replied on Tuesday, November 21, 2006

Ok, scratch that. Turns out that it wasn't the ValidationsTag but the simple fact of having to "Save" the XML file after I generate it. I'd generate and refresh it in XMLLSpy then the code generation would fail with the given error. However, if I click "Save" in XMLSpy then the CSLA code generates just fine.

So, now I'm generating code. Yay!

Will

Copyright (c) Marimer LLC