Binding Question

Binding Question

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


KickTheSky posted on Friday, May 02, 2008

    Here's the situation.  I have an Organization object that contains data on an Organization like name, phone number, ect...  This inherits from Business Base.  The Organization object has a child object, also inheriting from Business Base that is a singular Address.  Address is used in several places (Customers, Vendors, etc..)  So, the Organization has a property named Address of type Address.

Here is the problem.  Unit testing of the object everything works fine.  It persists, I can make changes to it. I can delete it.  No problem.

Get it to a WinForm and do binding.  Have a BindingSource bound to Organization.  I dragged on the fields for Name, Phone, Fax, ect from the Data Sources Tab.  I then expanded the Organization.Address to get the Address fields and dragged them on the form as well.  So far so good.  So, for example, the binding for the Street1TextBox would be something like Address.Street1.

Start up the app and load an existing Organization.  Loads up just fine.  Get all of the normal org data and their address as well.  Make a change to their address and save it.  Reload it and the address data is not changed.  Created a new Organization.  Could not save it as the address rules are not being unbroken when data is being entered in.

Anyone know how I can get read/write binding on the Address data instead of read-only?

sergeyb replied on Friday, May 02, 2008

I believe you need to have a separate binding source for Address, and bind address fields to that binding source.

 

Sergey Barskiy

Senior Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: KickTheSky [mailto:cslanet@lhotka.net]
Sent: Friday, May 02, 2008 1:03 PM
To: Sergey Barskiy
Subject: [CSLA .NET] Binding Question

 

    Here's the situation.  I have an Organization object that contains data on an Organization like name, phone number, ect...  This inherits from Business Base.  The Organization object has a child object, also inheriting from Business Base that is a singular Address.  Address is used in several places (Customers, Vendors, etc..)  So, the Organization has a property named Address of type Address.

Here is the problem.  Unit testing of the object everything works fine.  It persists, I can make changes to it. I can delete it.  No problem.

Get it to a WinForm and do binding.  Have a BindingSource bound to Organization.  I dragged on the fields for Name, Phone, Fax, ect from the Data Sources Tab.  I then expanded the Organization.Address to get the Address fields and dragged them on the form as well.  So far so good.  So, for example, the binding for the Street1TextBox would be something like Address.Street1.

Start up the app and load an existing Organization.  Loads up just fine.  Get all of the normal org data and their address as well.  Make a change to their address and save it.  Reload it and the address data is not changed.  Created a new Organization.  Could not save it as the address rules are not being unbroken when data is being entered in.

Anyone know how I can get read/write binding on the Address data instead of read-only?


KickTheSky replied on Friday, May 02, 2008

Just tried that and it did not work.  Created a seperate binding source for Address.  Bound the fields to it.  In the load event added code to bind the address data source to mCurrentOrganization.Address.  Still loads the data, still read-only (data is changable but does not save or enforce rules)

sergeyb replied on Friday, May 02, 2008

Let me make sure I got it right.   You set datasource for AddressBindingSource to CurrentOrganizationBindingSource and Member to “Address”?

 

Sergey Barskiy

Senior Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: KickTheSky [mailto:cslanet@lhotka.net]
Sent: Friday, May 02, 2008 1:28 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: Binding Question

 

Just tried that and it did not work.  Created a seperate binding source for Address.  Bound the fields to it.  In the load event added code to bind the address data source to mCurrentOrganization.Address.  Still loads the data, still read-only (data is changable but does not save or enforce rules)


KickTheSky replied on Friday, May 02, 2008

No, I set the DataSource to mCurrentOrganization.Address.  I did not use the member property at all.  Is that the problem?

ajj3085 replied on Friday, May 02, 2008

Probably.  the DataSource of the addressBindingSource should be set in the design to the organizationbindingsource.  The DataMember must be set to Address.

In code, you only set the DataSource for organizationBindingSource.  No need to do anything to the addressbindingsource to set it properly.

KickTheSky replied on Friday, May 02, 2008

Did exactly that and it is still not saving changes.

sergeyb replied on Friday, May 02, 2008

Hmm..  Sounds strange.  Could you double-check your objects next?  You can just set a breakpoint in your property setter for an address field and change that field in UI to see if your breakpoint is hit.  This should eliminate databindings from debugging process.

 

Sergey Barskiy

Senior Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: KickTheSky [mailto:cslanet@lhotka.net]
Sent: Friday, May 02, 2008 2:03 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: Binding Question

 

Did exactly that and it is still not saving changes.


KickTheSky replied on Friday, May 02, 2008

It is not hitting the property setter when the field is changed.

sergeyb replied on Friday, May 02, 2008

Now this is strange.  I am not quite sure where to go from here.  Sounds like the issue is definitely on the form, but I cannot think of what it might be.  Do you want to post your code?

 

Sergey Barskiy

Senior Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: KickTheSky [mailto:cslanet@lhotka.net]
Sent: Friday, May 02, 2008 2:23 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: RE: Binding Question

 

It is not hitting the property setter when the field is changed.


KickTheSky replied on Friday, May 02, 2008

Here is the code for the Organization...

using System;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Csla.Validation;
using Wemco.Library.Utility;

namespace Wemco.Library.Customer
{
    [Serializable()]
    public class Organization : BusinessBase<Organization>
    {
        #region BUSINESS METHODS

        private Guid _organizationId;
        private string _name = String.Empty;
        private string _phone = String.Empty;
        private string _fax = String.Empty;
        private byte[] _timestamp = new byteMusic [8];

        private Address _address = Address.NewAddress();
        private OrganizationCustomers _customers = OrganizationCustomers.NewOrganizationCustomers();

        [System.ComponentModel.DataObjectField(true, true)]
        public Guid OrganizationId
        {
            get
            {
                CanReadProperty(true);
                return _organizationId;
            }
        }

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

        public string Phone
        {
            get
            {
                CanReadProperty(true);
                return _phone;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_phone != value)
                {
                    _phone = value;
                    PropertyHasChanged("Phone");
                }
            }
        }


        public string Fax
        {
            get
            {
                CanReadProperty(true);
                return _fax;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_fax != value)
                {
                    _fax = value;
                    PropertyHasChanged("Fax");
                }
            }
        }

        public Address Address
        {
            get { return _address; }
       
        }

        public OrganizationCustomers Customers { get { return _customers; } }


        public override bool IsValid
        {
            get
            {
                return base.IsValid && _address.IsValid && _customers.IsValid;
            }
        }

        public override bool IsDirty
        {
            get
            {
                return base.IsDirty || _address.IsDirty || _customers.IsDirty;
            }
        }

        protected override object GetIdValue()
        {
            return _organizationId;
        }
        

        #endregion BUSINESS METHODS


        #region VALIDATION RULES


        protected override void AddBusinessRules()
        {
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "Name");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Name", 50));
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Phone", 15));
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Fax", 15));
        }


        #endregion VALIDATION RULES


        #region AUTHORIZTION RULES


        public static bool CanAddObject()
        {
            return true;
        }

        public static bool CanGetObject()
        {
            return true;
        }

        public static bool CanDeleteObject()
        {
            return true;
        }

        public static bool CanEditObject()
        {
            return true;
        }
       

        #endregion  AUTHORIZATION RULES



        #region FACTORY METHODS


        public static Organization NewOrganization()
        {
            if (!CanAddObject())
                throw new System.Security.SecurityException("User is not authorized to add an organization.");
            return DataPortal.Create<Organization>(null);
        }

        public static Organization GetOrganization(Guid id)
        {
            if (!CanGetObject())
                throw new System.Security.SecurityException("User is not authorized to view an Organization.");
            return DataPortal.Fetch<Organization>(new Criteria(id));
        }

        public static void DeleteOrganization(Guid id)
        {
            if (!CanDeleteObject())
                throw new System.Security.SecurityException("User is not authorized to delete an organization");
            DataPortal.Delete(new Criteria(id));
        }

        public override Organization Save()
        {
            if (IsDeleted && !CanDeleteObject())
                throw new System.Security.SecurityException("User is not authorized to delete an organization");
            else if (IsNew && !CanAddObject())
                throw new System.Security.SecurityException("User is not authorized to add an organization");
            else if (!CanEditObject())
                throw new System.Security.SecurityException("User is not authorized to update an organization");
            return base.Save();
        }

        private Organization()
        {   /* require use of factory methods */ }

        #endregion FACTORY METHODS


        #region DATA ACCESS


        [Serializable()]
        private class Criteria
        {
            private Guid _id;

            public Guid Id
            {
                get { return _id; }
            }

            public Criteria(Guid id)
            {
                _id = id;
            }
        }


        [RunLocal()]
        private void DataPortal_Create(Criteria criteria)
        {
            _organizationId = Guid.NewGuid();
            ValidationRules.CheckRules();
        }

        private void DataPortal_Fetch(Criteria criteria)
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_getOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", criteria.Id);

                    using (SafeDataReader dr = new SafeDataReader(cmd.ExecuteReader()))
                    {
                        dr.Read();
                        _organizationId = dr.GetGuid("organization_id");
                        _name = dr.GetString("name");
                        _phone = dr.GetString("phone");
                        _fax = dr.GetString("fax");
                        dr.GetBytes("last_changed", 0, _timestamp, 0, 8);
                        //load child objects             
                        _address = Address.GetAddress(dr);
                        dr.NextResult();
                        _customers = OrganizationCustomers.GetOrganizationCustomers(dr);
                    }
                }
                ValidationRules.CheckRules();
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Insert()
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                //insert the address first as the id is needed for the organization
                _address.InsertAddress(cnn);

                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_addOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", _organizationId);
                    cmd.Parameters.AddWithValue("@address_id", _address.AddressId);
                    cmd.Parameters.AddWithValue("@name", _name);
                    cmd.Parameters.AddWithValue("@phone", _phone);
                    cmd.Parameters.AddWithValue("@fax", _fax);
                    SqlParameter param = new SqlParameter("@last_changed", SqlDbType.Timestamp);
                    param.Direction = ParameterDirection.Output;
                    cmd.Parameters.Add(param);

                    cmd.ExecuteNonQuery();
                    _timestamp = (byte[])cmd.Parameters["@last_changed"].Value;
                }               
                //update the customers.
                _customers.Update(cnn, this);
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Update()
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                if (base.IsDirty)
                {
                    using (SqlCommand cmd = cnn.CreateCommand())
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.CommandText = "cust_updateOrganization";
                        cmd.Parameters.AddWithValue("@organization_id", _organizationId);
                        cmd.Parameters.AddWithValue("@name", _name);
                        cmd.Parameters.AddWithValue("@phone", _phone);
                        cmd.Parameters.AddWithValue("@fax", _fax);
                        cmd.Parameters.AddWithValue("@last_changed", _timestamp);
                        SqlParameter param = new SqlParameter("@newLastChanged", SqlDbType.Timestamp);
                        param.Direction = ParameterDirection.Output;
                        cmd.Parameters.Add(param);

                        cmd.ExecuteNonQuery();
                        _timestamp = (byte[])cmd.Parameters["@newLastChanged"].Value;
                    }
                }
                //update the child objects
                _address.UpdateAddress(cnn);
                //_addresses.Update(cnn, this);
                _customers.Update(cnn, this);
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_DeleteSelf()
        {
            DataPortal_Delete(new Criteria(_organizationId));
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        private void DataPortal_Delete(Criteria criteria)
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_deleteOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", criteria.Id);
                    cmd.ExecuteNonQuery();
                }
            }
        }


        #endregion DATA ACCESS

        #region Exists

        public static bool Exists(Guid id, string name)
        {
            ExistsCommand result;
            result = DataPortal.Execute<ExistsCommand>(new ExistsCommand(id, name));
            return result.Exists;
        }

        [Serializable()]
        private class ExistsCommand : CommandBase
        {

            private Guid _id;
            private string _name = String.Empty;
            private bool _exists;

            public bool Exists
            {
                get { return _exists; }
            }

            public ExistsCommand(Guid id, string name)
            {
                _id = id;
                _name = name;
            }

            protected override void DataPortal_Execute()
            {
                using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
                {
                    cnn.Open();
                    using (SqlCommand cmd = cnn.CreateCommand())
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.CommandText = "cust_existsOrganization";
                        cmd.Parameters.AddWithValue("@organization_id", _id);
                        cmd.Parameters.AddWithValue("@name", _name);
                        int count = (int)cmd.ExecuteScalar();
                        _exists = (count > 0);
                    }
                }
            }
        }

        #endregion
    }
}


And for the Address


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

namespace Wemco.Library.Utility
{
    [Serializable()]
    public class Address : BusinessBase<Address>
    {
        #region BUSINESS METHODS

        private Guid _addressId;
        private string _street1 = String.Empty;
        private string _street2 = String.Empty;
        private string _attention = String.Empty;
        private string _city = String.Empty;
        private string _countryCode = String.Empty;
        private string _stateCode = String.Empty;
        private string _postalCode = String.Empty;
        private byte[] _timestamp = new byteMusic [8];

        public Guid AddressId
        {
            get
            {
                CanReadProperty(true);
                return _addressId;
            }
        }

        public string Street1
        {
            get
            {
                CanReadProperty(true);
                return _street1;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_street1 != value)
                {
                    _street1 = value;
                    PropertyHasChanged("Street1");
                }
            }
        }

        public string Street2
        {
            get
            {
                CanReadProperty(true);
                return _street2;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_street2 != value)
                {
                    _street2 = value;
                    PropertyHasChanged("Street2");
                }
            }
        }

        public string Attention
        {
            get
            {
                CanReadProperty(true);
                return _attention;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_attention != value)
                {
                    _attention = value;
                    PropertyHasChanged("Attention");
                }
            }
        }

        public string City
        {
            get
            {
                CanReadProperty(true);
                return _city;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_city != value)
                {
                    _city = value;
                    PropertyHasChanged("City");
                }
            }
        }

        public string PostalCode
        {
            get
            {
                CanReadProperty(true);
                return _postalCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_postalCode != value)
                {
                    _postalCode = value;
                    PropertyHasChanged("PostalCode");
                }
            }
        }

        public string CountryCode
        {
            get
            {
                CanReadProperty(true);
                return _countryCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = string.Empty;
                if (_countryCode != value)
                {
                    _countryCode = value;
                    PropertyHasChanged("CountryCode");
                }
            }
        }

        public string StateCode
        {
            get
            {
                CanReadProperty(true);
                return _stateCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = string.Empty;
                if (_stateCode != value)
                {
                    _stateCode = value;
                    PropertyHasChanged("StateCode");
                }
            }
        }

        protected override object GetIdValue()
        {
            return _addressId;
        }

        #endregion BUSINESS METHODS

        #region Validation Rules

        protected override void AddBusinessRules()
        {
            // Street1 - required, max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "Street1");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Street1", 50));
            // Street2 - max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Street2", 50));
            // Attention - max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Attention", 50));
            // City -required,  max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "City");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("City", 50));
            // CountryCode - required, lookup
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "CountryCode");
            // PostalCode - required, max 20 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "PostalCode");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("PostalCode", 20));           
        }

        #endregion


        #region FACTORY METHODS

        //Factory methods will be implemented at the subclass level

        public static Address NewAddress()
        {
            return new Address();
        }

        public static Address GetAddress(SafeDataReader dr)
        {
            return new Address(dr);
        }


        protected Address()
        {
            MarkAsChild();
            _addressId = Guid.NewGuid();
            _countryCode = CountryList.DEFAULT_COUNTRY;
            ValidationRules.CheckRules();
        }

        protected Address(SafeDataReader dr)
        {
            MarkAsChild();
            Fetch(dr);
            ValidationRules.CheckRules();
        }

        #endregion

        #region DATA ACCESS

        public void Fetch(SafeDataReader dr)
        {
            _addressId = dr.GetGuid("address_id");
            _street1 = dr.GetString("street1");
            _street2 = dr.GetString("street2");
            _attention = dr.GetString("attention");
            _city = dr.GetString("city");
            _countryCode = dr.GetString("country_code");
            _stateCode = dr.GetString("state_code");
            _postalCode = dr.GetString("postal_code");
            dr.GetBytes("last_changed", 0, _timestamp, 0, 8);
            MarkOld();
        }

        public void InsertAddress(SqlConnection cnn)
        {
            using (SqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = "util_addAddress";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@address_id", _addressId);
                cmd.Parameters.AddWithValue("@street1", _street1);
                cmd.Parameters.AddWithValue("@street2", _street2);
                cmd.Parameters.AddWithValue("@city", _city);
                cmd.Parameters.AddWithValue("@country_code", _countryCode);
                cmd.Parameters.AddWithValue("@state_code", _stateCode);
                cmd.Parameters.AddWithValue("@postal_code", _postalCode);
                cmd.Parameters.AddWithValue("@attention", _attention);
                SqlParameter param = new SqlParameter("@last_changed", SqlDbType.Timestamp);
                param.Direction = ParameterDirection.Output;
                cmd.Parameters.Add(param);

                cmd.ExecuteNonQuery();

                //set the output values
                _timestamp = (byte[])cmd.Parameters["@last_changed"].Value;
            }
            MarkOld();
        }

        public void UpdateAddress(SqlConnection cnn)
        {
            using (SqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = "util_updateAddress";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@address_id", _addressId);
                cmd.Parameters.AddWithValue("@street1", _street1);
                cmd.Parameters.AddWithValue("@street2", _street2);
                cmd.Parameters.AddWithValue("@city", _city);
                cmd.Parameters.AddWithValue("@country_code", _countryCode);
                cmd.Parameters.AddWithValue("@state_code", _stateCode);
                cmd.Parameters.AddWithValue("@postal_code", _postalCode);
                cmd.Parameters.AddWithValue("@attention", _attention);
                cmd.Parameters.AddWithValue("@last_changed", _timestamp);
                SqlParameter param = new SqlParameter("@newLastChanged", SqlDbType.Timestamp);
                param.Direction = ParameterDirection.Output;
                cmd.Parameters.Add(param);
                cmd.ExecuteNonQuery();

                //set the output values
                _timestamp = (byte[])cmd.Parameters["@newLastChanged"].Value;
            }
            MarkOld();
        }


        #endregion


    }

}

sergeyb replied on Friday, May 02, 2008

I am at a loss.  It all looks good.  The only thing I notices that if you load organization without an address id DB.  The issue must be in the form itself since your breakpoint is not hit.  Sorry I could not be of any more help.

 

Sergey Barskiy

Senior Consultant

office: 678.405.0687 | mobile: 404.388.1899

cid:_2_0648EA840648E85C001BBCB886257279
Microsoft Worldwide Partner of the Year | Custom Development Solutions, Technical Innovation

 

From: KickTheSky [mailto:cslanet@lhotka.net]
Sent: Friday, May 02, 2008 4:02 PM
To: Sergey Barskiy
Subject: Re: [CSLA .NET] RE: RE: RE: RE: Binding Question

 

Here is the code for the Organization...

using System;
using System.Data;
using System.Data.SqlClient;
using Csla;
using Csla.Data;
using Csla.Validation;
using Wemco.Library.Utility;

namespace Wemco.Library.Customer
{
    [Serializable()]
    public class Organization : BusinessBase<Organization>
    {
        #region BUSINESS METHODS

        private Guid _organizationId;
        private string _name = String.Empty;
        private string _phone = String.Empty;
        private string _fax = String.Empty;
        private byte[] _timestamp = new byteMusic <img src=">;

        private Address _address = Address.NewAddress();
        private OrganizationCustomers _customers = OrganizationCustomers.NewOrganizationCustomers();

        [System.ComponentModel.DataObjectField(true, true)]
        public Guid OrganizationId
        {
            get
            {
                CanReadProperty(true);
                return _organizationId;
            }
        }

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

        public string Phone
        {
            get
            {
                CanReadProperty(true);
                return _phone;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_phone != value)
                {
                    _phone = value;
                    PropertyHasChanged("Phone");
                }
            }
        }


        public string Fax
        {
            get
            {
                CanReadProperty(true);
                return _fax;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_fax != value)
                {
                    _fax = value;
                    PropertyHasChanged("Fax");
                }
            }
        }

        public Address Address
        {
            get { return _address; }
       
        }

        public OrganizationCustomers Customers { get { return _customers; } }


        public override bool IsValid
        {
            get
            {
                return base.IsValid && _address.IsValid && _customers.IsValid;
            }
        }

        public override bool IsDirty
        {
            get
            {
                return base.IsDirty || _address.IsDirty || _customers.IsDirty;
            }
        }

        protected override object GetIdValue()
        {
            return _organizationId;
        }
        

        #endregion BUSINESS METHODS


        #region VALIDATION RULES


        protected override void AddBusinessRules()
        {
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "Name");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Name", 50));
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Phone", 15));
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Fax", 15));
        }


        #endregion VALIDATION RULES


        #region AUTHORIZTION RULES


        public static bool CanAddObject()
        {
            return true;
        }

        public static bool CanGetObject()
        {
            return true;
        }

        public static bool CanDeleteObject()
        {
            return true;
        }

        public static bool CanEditObject()
        {
            return true;
        }
       

        #endregion  AUTHORIZATION RULES



        #region FACTORY METHODS


        public static Organization NewOrganization()
        {
            if (!CanAddObject())
                throw new System.Security.SecurityException("User is not authorized to add an organization.");
            return DataPortal.Create<Organization>(null);
        }

        public static Organization GetOrganization(Guid id)
        {
            if (!CanGetObject())
                throw new System.Security.SecurityException("User is not authorized to view an Organization.");
            return DataPortal.Fetch<Organization>(new Criteria(id));
        }

        public static void DeleteOrganization(Guid id)
        {
            if (!CanDeleteObject())
                throw new System.Security.SecurityException("User is not authorized to delete an organization");
            DataPortal.Delete(new Criteria(id));
        }

        public override Organization Save()
        {
            if (IsDeleted && !CanDeleteObject())
                throw new System.Security.SecurityException("User is not authorized to delete an organization");
            else if (IsNew && !CanAddObject())
                throw new System.Security.SecurityException("User is not authorized to add an organization");
            else if (!CanEditObject())
                throw new System.Security.SecurityException("User is not authorized to update an organization");
            return base.Save();
        }

        private Organization()
        {   /* require use of factory methods */ }

        #endregion FACTORY METHODS


        #region DATA ACCESS


        [Serializable()]
        private class Criteria
        {
            private Guid _id;

            public Guid Id
            {
                get { return _id; }
            }

            public Criteria(Guid id)
            {
                _id = id;
            }
        }


        [RunLocal()]
        private void DataPortal_Create(Criteria criteria)
        {
            _organizationId = Guid.NewGuid();
            ValidationRules.CheckRules();
        }

        private void DataPortal_Fetch(Criteria criteria)
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_getOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", criteria.Id);

                    using (SafeDataReader dr = new SafeDataReader(cmd.ExecuteReader()))
                    {
                        dr.Read();
                        _organizationId = dr.GetGuid("organization_id");
                        _name = dr.GetString("name");
                        _phone = dr.GetString("phone");
                        _fax = dr.GetString("fax");
                        dr.GetBytes("last_changed", 0, _timestamp, 0, 8);
                        //load child objects             
                        _address = Address.GetAddress(dr);
                        dr.NextResult();
                        _customers = OrganizationCustomers.GetOrganizationCustomers(dr);
                    }
                }
                ValidationRules.CheckRules();
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Insert()
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                //insert the address first as the id is needed for the organization
                _address.InsertAddress(cnn);

                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_addOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", _organizationId);
                    cmd.Parameters.AddWithValue("@address_id", _address.AddressId);
                    cmd.Parameters.AddWithValue("@name", _name);
                    cmd.Parameters.AddWithValue("@phone", _phone);
                    cmd.Parameters.AddWithValue("@fax", _fax);
                    SqlParameter param = new SqlParameter("@last_changed", SqlDbType.Timestamp);
                    param.Direction = ParameterDirection.Output;
                    cmd.Parameters.Add(param);

                    cmd.ExecuteNonQuery();
                    _timestamp = (byte[])cmd.Parameters["@last_changed"].Value;
                }               
                //update the customers.
                _customers.Update(cnn, this);
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_Update()
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                if (base.IsDirty)
                {
                    using (SqlCommand cmd = cnn.CreateCommand())
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.CommandText = "cust_updateOrganization";
                        cmd.Parameters.AddWithValue("@organization_id", _organizationId);
                        cmd.Parameters.AddWithValue("@name", _name);
                        cmd.Parameters.AddWithValue("@phone", _phone);
                        cmd.Parameters.AddWithValue("@fax", _fax);
                        cmd.Parameters.AddWithValue("@last_changed", _timestamp);
                        SqlParameter param = new SqlParameter("@newLastChanged", SqlDbType.Timestamp);
                        param.Direction = ParameterDirection.Output;
                        cmd.Parameters.Add(param);

                        cmd.ExecuteNonQuery();
                        _timestamp = (byte[])cmd.Parameters["@newLastChanged"].Value;
                    }
                }
                //update the child objects
                _address.UpdateAddress(cnn);
                //_addresses.Update(cnn, this);
                _customers.Update(cnn, this);
            }
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_DeleteSelf()
        {
            DataPortal_Delete(new Criteria(_organizationId));
        }

        [Transactional(TransactionalTypes.TransactionScope)]
        private void DataPortal_Delete(Criteria criteria)
        {
            using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
            {
                cnn.Open();
                using (SqlCommand cmd = cnn.CreateCommand())
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "cust_deleteOrganization";
                    cmd.Parameters.AddWithValue("@organization_id", criteria.Id);
                    cmd.ExecuteNonQuery();
                }
            }
        }


        #endregion DATA ACCESS

        #region Exists

        public static bool Exists(Guid id, string name)
        {
            ExistsCommand result;
            result = DataPortal.Execute<ExistsCommand>(new ExistsCommand(id, name));
            return result.Exists;
        }

        [Serializable()]
        private class ExistsCommand : CommandBase
        {

            private Guid _id;
            private string _name = String.Empty;
            private bool _exists;

            public bool Exists
            {
                get { return _exists; }
            }

            public ExistsCommand(Guid id, string name)
            {
                _id = id;
                _name = name;
            }

            protected override void DataPortal_Execute()
            {
                using (SqlConnection cnn = new SqlConnection(Database.WemcoConnection))
                {
                    cnn.Open();
                    using (SqlCommand cmd = cnn.CreateCommand())
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.CommandText = "cust_existsOrganization";
                        cmd.Parameters.AddWithValue("@organization_id", _id);
                        cmd.Parameters.AddWithValue("@name", _name);
                        int count = (int)cmd.ExecuteScalar();
                        _exists = (count > 0);
                    }
                }
            }
        }

        #endregion
    }
}


And for the Address


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

namespace Wemco.Library.Utility
{
    [Serializable()]
    public class Address : BusinessBase<Address>
    {
        #region BUSINESS METHODS

        private Guid _addressId;
        private string _street1 = String.Empty;
        private string _street2 = String.Empty;
        private string _attention = String.Empty;
        private string _city = String.Empty;
        private string _countryCode = String.Empty;
        private string _stateCode = String.Empty;
        private string _postalCode = String.Empty;
        private byte[] _timestamp = new byteMusic <img src=">;

        public Guid AddressId
        {
            get
            {
                CanReadProperty(true);
                return _addressId;
            }
        }

        public string Street1
        {
            get
            {
                CanReadProperty(true);
                return _street1;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_street1 != value)
                {
                    _street1 = value;
                    PropertyHasChanged("Street1");
                }
            }
        }

        public string Street2
        {
            get
            {
                CanReadProperty(true);
                return _street2;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_street2 != value)
                {
                    _street2 = value;
                    PropertyHasChanged("Street2");
                }
            }
        }

        public string Attention
        {
            get
            {
                CanReadProperty(true);
                return _attention;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_attention != value)
                {
                    _attention = value;
                    PropertyHasChanged("Attention");
                }
            }
        }

        public string City
        {
            get
            {
                CanReadProperty(true);
                return _city;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_city != value)
                {
                    _city = value;
                    PropertyHasChanged("City");
                }
            }
        }

        public string PostalCode
        {
            get
            {
                CanReadProperty(true);
                return _postalCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = String.Empty;
                if (_postalCode != value)
                {
                    _postalCode = value;
                    PropertyHasChanged("PostalCode");
                }
            }
        }

        public string CountryCode
        {
            get
            {
                CanReadProperty(true);
                return _countryCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = string.Empty;
                if (_countryCode != value)
                {
                    _countryCode = value;
                    PropertyHasChanged("CountryCode");
                }
            }
        }

        public string StateCode
        {
            get
            {
                CanReadProperty(true);
                return _stateCode;
            }
            set
            {
                CanWriteProperty(true);
                if (value == null) value = string.Empty;
                if (_stateCode != value)
                {
                    _stateCode = value;
                    PropertyHasChanged("StateCode");
                }
            }
        }

        protected override object GetIdValue()
        {
            return _addressId;
        }

        #endregion BUSINESS METHODS

        #region Validation Rules

        protected override void AddBusinessRules()
        {
            // Street1 - required, max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "Street1");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Street1", 50));
            // Street2 - max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Street2", 50));
            // Attention - max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("Attention", 50));
            // City -required,  max 50 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "City");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("City", 50));
            // CountryCode - required, lookup
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "CountryCode");
            // PostalCode - required, max 20 char
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringRequired), "PostalCode");
            ValidationRules.AddRule(new RuleHandler(CommonRules.StringMaxLength),
                new CommonRules.MaxLengthRuleArgs("PostalCode", 20));           
        }

        #endregion


        #region FACTORY METHODS

        //Factory methods will be implemented at the subclass level

        public static Address NewAddress()
        {
            return new Address();
        }

        public static Address GetAddress(SafeDataReader dr)
        {
            return new Address(dr);
        }


        protected Address()
        {
            MarkAsChild();
            _addressId = Guid.NewGuid();
            _countryCode = CountryList.DEFAULT_COUNTRY;
            ValidationRules.CheckRules();
        }

        protected Address(SafeDataReader dr)
        {
            MarkAsChild();
            Fetch(dr);
            ValidationRules.CheckRules();
        }

        #endregion

        #region DATA ACCESS

        public void Fetch(SafeDataReader dr)
        {
            _addressId = dr.GetGuid("address_id");
            _street1 = dr.GetString("street1");
            _street2 = dr.GetString("street2");
            _attention = dr.GetString("attention");
            _city = dr.GetString("city");
            _countryCode = dr.GetString("country_code");
            _stateCode = dr.GetString("state_code");
            _postalCode = dr.GetString("postal_code");
            dr.GetBytes("last_changed", 0, _timestamp, 0, 8);
            MarkOld();
        }

        public void InsertAddress(SqlConnection cnn)
        {
            using (SqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = "util_addAddress";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@address_id", _addressId);
                cmd.Parameters.AddWithValue("@street1", _street1);
                cmd.Parameters.AddWithValue("@street2", _street2);
                cmd.Parameters.AddWithValue("@city", _city);
                cmd.Parameters.AddWithValue("@country_code", _countryCode);
                cmd.Parameters.AddWithValue("@state_code", _stateCode);
                cmd.Parameters.AddWithValue("@postal_code", _postalCode);
                cmd.Parameters.AddWithValue("@attention", _attention);
                SqlParameter param = new SqlParameter("@last_changed", SqlDbType.Timestamp);
                param.Direction = ParameterDirection.Output;
                cmd.Parameters.Add(param);

                cmd.ExecuteNonQuery();

                //set the output values
                _timestamp = (byte[])cmd.Parameters["@last_changed"].Value;
            }
            MarkOld();
        }

        public void UpdateAddress(SqlConnection cnn)
        {
            using (SqlCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = "util_updateAddress";
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@address_id", _addressId);
                cmd.Parameters.AddWithValue("@street1", _street1);
                cmd.Parameters.AddWithValue("@street2", _street2);
                cmd.Parameters.AddWithValue("@city", _city);
                cmd.Parameters.AddWithValue("@country_code", _countryCode);
                cmd.Parameters.AddWithValue("@state_code", _stateCode);
                cmd.Parameters.AddWithValue("@postal_code", _postalCode);
                cmd.Parameters.AddWithValue("@attention", _attention);
                cmd.Parameters.AddWithValue("@last_changed", _timestamp);
                SqlParameter param = new SqlParameter("@newLastChanged", SqlDbType.Timestamp);
                param.Direction = ParameterDirection.Output;
                cmd.Parameters.Add(param);
                cmd.ExecuteNonQuery();

                //set the output values
                _timestamp = (byte[])cmd.Parameters["@newLastChanged"].Value;
            }
            MarkOld();
        }


        #endregion


    }

}



JonnyBee replied on Sunday, May 04, 2008

Well, first of all - you are appying your datamodel to your business objects and windows databinding is not "flexible" for handling 1 to 1 relationships - only 1 to n relationships. (including the ErrorProvider and other helpful components).

Your datamodel should NOT be applied to your business objects. If organization has only one address it should be properties IN your Organization object. You could in turn use your address object to fetch/save values in the DP_XYZ methods on your Organzation object.

/jonny

ajj3085 replied on Monday, May 05, 2008

That's not really true.  As explained, adding a second binding source who's DataSource is the primary binding source and it's data member set properly will work fine.  There's nothing inherent with windows databinding that wouldn't allow this to work, and normally it does.

Creating Organization as a facade which holds the address is a fine solution as well, but if the Address can be reused there's nothing wrong with the original solution either.

I suspect the OP's problem is that the databinding isn't being setup / worked with properly, but without seeing code in the form we don't know.

Copyright (c) Marimer LLC