Design questions

Design questions

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


dnebula posted on Tuesday, July 04, 2006

I'm creating an application for a real estate business. One of the most important objects is "Property" (in this context property is a house, flat and so on) and I have a few questions on how to design this object.

1) A Property object has certain properties (read: fields) like PropertyType (house, flat etc.), OwnershipType (owned, collective owned etc.) In the database the property table just have foreign keys for these kind of properties (PropertyTypeId, OwnershipTypeId).

One use case is to display all info of a Property including type and ownership type. This implies that I should fetch the accual name of the property type and ownership type as well as id. My solution would be to have a Property object include a (redonly) property TypeName as well as TypeId. I ommit ownership type in the following discussion since I think you get the point =)

Another use case involves changing PropertyType. To handle this i make TypeId read/write. Changing would be as simple as setting the new id and save the object. Obviously I would need to reload the Property object to uptade the TypeName field. This seems a bit akward.

To allow users to se what types they can set I just have a PropertyTypes object derived from NameValueListBase.

Does this seem like the right way of doing this?

2) A Property has a Broker (FK BrokerId in the db). As described above I need to display Property info and that includes info on the broker. This implies that the broker should be a child object of Property. But what if I want to assign another broker to the property? Exposing a BrokerId field in the Property object would be an option (pretty much like the type example above). But I feels wrong to have a Broker child object as well as an BrokerId field. 

I must also be able to load and edit just a broker, so it should also be a editable root. Smells like switchable and that feels bad too.

Any idea how to solve that?

tetranz replied on Tuesday, July 04, 2006

Hi dnebula

Many objects have this situation, ie they need readonly data from a related object. I've played with various ways of handling it. Here's what I've settled on. Let's consider your Property object (could be an awkward name Smile [:)] ) which needs info about its related broker but broker is also separately edited. Property and Broker are both editable roots. I assume Property has a variable called _brokerId.

Inside Property, build a class like this:

public class BrokerInfo
{
    private int _id
    public int Id
    {
       get { return _id; }
    }

    private string _name
    public string Name
    {
       get { return _name; }
    }

    private string _phoneNumber
    public string PhoneNumber
    {
       get { return _phoneNumber; }
    }

    private bool _isValid;
    public bool IsValid
    {
       get { return _isValid; }
    }

    public void Clear()
    }
       _id = 0;
       _name = String.Empty;
       _phoneNumber = String.Empty;
       _isValid = false;
    }

    public Clear(int id)
    {
       Clear();
       _id = id;
    }

    public BrokerInfo()
    {
       Clear();
    }

    public void Update(Broker broker)
    {
       _id = broker.Id;
       _name = broker.Name;
       _phoneNumber = broker.PhoneNumber;
       _isValid = true;
    }

    public void Update(int id, string name, string phoneNumber)
    {
       _id = id;
       _name = name;
       _phoneNumber = phoneNumber;
       _isValid = true;
    }
}

private BrokerInfo _brokerInfo = new BrokerInfo();

public BrokeInfo Broker
{
    get
    {
       if (_brokerInfo.Id != _brokerId)
       {
            Broker broker = Broker.GetBroker(_brokerId);
            if (broker == null)
            {
                _brokerInfo.Clear(_brokerId);
            }
            else
            {
                _brokerInfo.Update(broker);
            }
             return _brokerInfo;
       }
    }
}

That's the key parts of it. The general idea is that its a cache. _brokerInfo remembers the brokerId that its data refers to, or the id of the last fetch attempt if invalid, so you'll only fetch a Broker object when you really need to and not repeatedly get the same one.

The Update method with separate properties is useful in your DataPortal_Fetch because you can probably get the property and broker data in one joined table SQL query so you load up _brokerInfo without needing to grab a Broker object.

On your Windows form for editing a Property, you can happily bind readonly fields to _property.Broker.Name and _property.Broker.PhoneNumber. You can't quite do that directly by point and click. When you select DataBindings for the control, you can select Broker from the list of bindingSource members but not the members of Broker. All you need to do then is manually add the .Name or .PhoneNumber.

I've modified my BO's so that their factory methods return null if the requested item doesn't exist.

The IsValid field is useful to show if BrokerId relates to a valid Broker. I've found it useful to expose it as a direct property of Property ie

public bool BrokerIsValid
{
    get { return _brokerInfo.IsValid; }
}

Property can have a business rule saying that BrokerIsValid must be true. Now, BrokerIsValid can be bound to an invisible (size = 0,0) checkbox. If you use an errorProvider then it will provide a nice indication if you haven't selected a valid broker. You can place the checkbox whereever you want the error indicator to appear. I guess you can tie the rule directly to BrokerId but that might be a numeric that you don't want to show on the form. To make error stuff work properly you need the following on the Property.BrokerId property setter just before PropertyHasChanged();

OnPropertyChanged("BrokerIsValid");
ValidationRules.CheckRules("BrokerIsValid");

I usually put OnPropertyChanged("BrokerInfo"); in there even if I'm not error checking because that means I can change the BrokerId and the Name and PhoneNumber fields will immediately change or go blank if Broker is invalid. That seems to work even without the OnPropertyChanged("BrokerInfo") which I don't fully understand. It seems that databinding refreshes all fields more often than I expect.

Well... that's about it. You could argue if it okay to use an editable root Broker as a means of just grabbing data. More correct would be have a readonly Broker but if the editable Broker is not loading child objects or doing anything heavy then it seems reasonable to use it and throw it away. Of course in that Get code when you need to read info about a different broker you can do whatever you like to get the data.

Cheers
Ross

dnebula replied on Tuesday, July 11, 2006

Thanks Ross, thats is a nice solution. I'll go with that one.

While I could use the same idea for the TypeId/Name problem, it will result in a lot of objects (I have a lot of those Id/Name pairs in the property object).

For each one I would need a RO SomeTypeInfo and a full SomeType BO to load the data.
I'm thiking I might be better of just exposing a R/W SomeTypeId and a RO SomeTypeName. The RO property would just look up the name in a cached SomeTypeNameValueList. Any thoughts on this?

Thanks,
Jonas

Copyright (c) Marimer LLC