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
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?
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
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)
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
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.
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
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.
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
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 byte">;
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 byte">;
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
}
}
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
Copyright (c) Marimer LLC