Accessor Issue

  • Thread starter Thread starter Steven Wolf
  • Start date Start date
S

Steven Wolf

Hi guys,

maybe you can help me again in developing my bussiness project for a
company..


i make sure, that each property of an entity, mark it self dirty when
data get changed.. thats the code:
private Address address;

....

/// <summary>
/// Set or return an address object
/// </summary>

class Facility : EntityObject
{

[EntityMemberAttribute]
public Address Address
{
get { return this.address; }
set { base.MarkDirty(); this.address = value; }
}


In this case, the address object i return here, has his own members,
like: Street, Zip, City..

So, i can access them easily by: someFacility.Address.City;


the problem comes, when i try to change the city, for example:

someFacility.Address.City = "New York";


the facility class does'nt get dirty, because the someFacility.Address
property use the get accessor in order to return the address, and the
address itself use finaly the set-accessor..


is there any possibility to fix that problem, instead creating a new
address object and put that on the facility? (someFacility.Address =
new Address(... )


steven.
 
Steven,

You would have to have each property on the Address class call the
MarkDirty method in order to specify that the property has changed.
 
The first question I would have to ask is whether the Address is
intrinsically a part of Facility, or a separate thing to which Facility
refers. I'm speaking here in logical terms rather than in code terms.
Is it really true that changing the City of an Address makes the
Facility dirty and therefore needing to be written back to the
database?

Let's assume that it is true.

I would solve this problem by adding functionality to Address. I would
give it its own dirty flag and MakeDirty() method, just as you did for
Facility.

Once you have that, you have two choices as to how to handle the
aggregation problem.

The first is to change the IsDirty property of Facility to check each
of its aggregate components, like this:

public bool IsDirty
{
get
{
return this.dirty || this.address.IsDirty || this...IsDirty ||
....;
}
}

That is probably the simplest way to solve the problem: each aggregated
structure keeps its own dirty information, and aggregates such as
Facility check them whenever necessary.

However, there is also a way to keep Facility's dirty flag updated
directly. You could have Address publish a IsDirtyChanged event that
fires whenever the Address becomes dirty (or un-dirty, if you allow
that). Facility could then subscribe to that event for its Address and
update its own dirty information accordingly.

This second method is a pain in the butt, because every time the caller
says

myFacility.Address = new Address(...);

or something like that, Facility has to remember to disconnect its
event handler from the Address that it has at the moment, assign the
new Address, and then connects its event handler to the new Address.

I like the first method better, myself. It's simpler and easier to
maintain.
 
hi nicholas,

the address class is independent, so in my case, i have to tell the
parent class to mark itself as dirty on changing in the address class.

steven.




Nicholas Paldino said:
Steven,

You would have to have each property on the Address class call the
MarkDirty method in order to specify that the property has changed.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Steven Wolf said:
Hi guys,

maybe you can help me again in developing my bussiness project for a
company..


i make sure, that each property of an entity, mark it self dirty when
data get changed.. thats the code:
private Address address;

....

/// <summary>
/// Set or return an address object
/// </summary>

class Facility : EntityObject
{

[EntityMemberAttribute]
public Address Address
{
get { return this.address; }
set { base.MarkDirty(); this.address = value; }
}


In this case, the address object i return here, has his own members,
like: Street, Zip, City..

So, i can access them easily by: someFacility.Address.City;


the problem comes, when i try to change the city, for example:

someFacility.Address.City = "New York";


the facility class does'nt get dirty, because the someFacility.Address
property use the get accessor in order to return the address, and the
address itself use finaly the set-accessor..


is there any possibility to fix that problem, instead creating a new
address object and put that on the facility? (someFacility.Address =
new Address(... )


steven.
 
hi bruce,

The first question I would have to ask is whether the Address is
intrinsically a part of Facility, or a separate thing to which Facility
refers. I'm speaking here in logical terms rather than in code terms.

the address class is independent/seperated, and can be use in other
classes.. an user could have an address too ( but i dont provide that
now, since a user is hooked to a facility), so i would use the same
address class as the facility do.

Is it really true that changing the City of an Address makes the
Facility dirty and therefore needing to be written back to the
database?

yes thats true.
Let's assume that it is true.

I would solve this problem by adding functionality to Address. I would
give it its own dirty flag and MakeDirty() method, just as you did for
Facility.

yes i do that already.

Once you have that, you have two choices as to how to handle the
aggregation problem.

The first is to change the IsDirty property of Facility to check each
of its aggregate components, like this:

public bool IsDirty
{
get
{
return this.dirty || this.address.IsDirty || this...IsDirty ||
...;
}
}

well, i cant to that, because the facility is derived from a base
class, and the base class carry all those isDirty, isNew... flags and
some other important things..

see my code before... ( ..base.MarkDirty(); )


However, there is also a way to keep Facility's dirty flag updated
directly. You could have Address publish a IsDirtyChanged event that
fires whenever the Address becomes dirty (or un-dirty, if you allow
that). Facility could then subscribe to that event for its Address and
update its own dirty information accordingly.

well, that sounds good..
but i have an entity, called contact. i store there all user
informations and i have there 4 similar objects:

public class Contact : EntityObject, ILazyLoading
{

...
private PhoneNumber phone;
private PhoneNumber fax;
private PhoneNumber mobile;
private EMail eMail;
...


the PhoneNumber class, store the internation area code, area code, and
the call number. i like to go this way instead store the numbers as
strings. the same thing for the email, to provide some basic
email-address validations. all those classes provide properties and
mark them self as dirty too, but again i have to mark, in this case,
the contact class as dirty, when for example the area code of the
PhoneNumber class get changed.

so, in my case, each entity (facility, contact..) would subscribe to
my "custom types" events?


This second method is a pain in the butt, because every time the caller
says

myFacility.Address = new Address(...);

or something like that, Facility has to remember to disconnect its
event handler from the Address that it has at the moment, assign the
new Address, and then connects its event handler to the new Address.

oh yes, i also try to keep my entites as simple as possible, but thats
a mass a little..

anyway, thank you for your support.
 
The first is to change the IsDirty property of Facility to check
each
well, i cant to that, because the facility is derived from a base
class, and the base class carry all those isDirty, isNew... flags and
some other important things..
see my code before... ( ..base.MarkDirty(); )

Yes, you still can. You should do it like this:

public class BaseClass
{
private bool _isDirty = false;

...
public void MakeDirty()
{
this._isDirty = true;
}

public virtual bool IsDirty
{
get { return this._isDirty; }
}
}

public class Facility : BaseClass
{
private Address _facilityAddress;
...
public override bool IsDirty
{
get { return base.IsDirty || this._facilityAddress.IsDirty ||
.... ; }
}
}

You should have an IsDirty property anyway... nobody should be looking
at the local isDirty flag in the base class. That should be private.
So, all you do is declare the property virtual and then override it in
classes that have complex fields like Addresses and PhoneNumbers.

I think that this is much cleaner and easier than messing with events,
etc.
 
You should (almost) always make fields private. You should (almost)
always expose fields to inheriting classes and to the outside world via
properties. This allows you to do things like what I did in the code
example: make a property do more than just return a field value.

In my code example, the "_isDirty" flag tells you only if the fields
directly stored by Facility have been changed. "_isDirty" _doesn't_
tell you whether anything inside Address has been changed. That's why
the IsDirty property (which is different from the "_isDirty" flag) does
extra work: it knows that it has to check _isDirty _plus_ the IsDirty
properties of any composite objects that are part of Facility.

Your session objects should look to the IsDirty property (not the
field) to see whether to write the entity back to the database. (They
won't be able to look at the field anyway, because it's now private.)

Yours is a classic example of why it's better to never to expose
fields, and expose properties instead: what you thought, in your
original design, was a simple boolean flag test (just test the _isDirty
flag) turned out to be more complicated. If you expose properties you
can always add more code to the get accessor. You can also override
properties in child classes and make them more sophisticated than in
the base class. You can't do any of that with fields.

DateTime is a struct, not a class. It uses value semantics. So, if you
have a DateTime in your Facility:

public class Facility : BaseClass
{
private DateTime _whenBuilt;
...
public DateTime WhenBuilt
{
get { return this._whenBuilt; }
set { this._whenBuilt = value; MakeDirty(); }
}
}

....you cannot, in fact, do this:

myFacility.WhenBuilt.AddDays(10);

If you look back at myFacility, you'll see that nothing has happened to
the date! You need to read up on value versus reference types to really
understand why, but the quick answer is that the DateTime is copied
onto the stack to return it from the WhenBuilt property, so the
AddDays() method adds 10 days to a temporary copy, not the version you
store inside your Facility class.

So, if you have fields that are structs, then they are safe.

If, however, you have a field that is a reference to a class that
someone else created and you can't modify, then you are correct: you
have two choices.

1. Subclass the class and add the "dirty" logic in the subclass.
Personally, I think that this is ugly.

2. Change the property that gets / sets this object to store a copy of
it:

public OtherClass OtherProperty
{
get { return this._other; }
set { this._other = value; this._otherCopy = value.Clone();
MakeDirty(); }
}

now you can change your IsDirty property to compare the two items to
see if they're still the same:

public bool IsDirty
{
get
{
bool dirty = this._isDirty || this._address.IsDirty ||
!this._other.Equals(this._otherCopy);
}
}

Since your caller can only get the original object (and use its methods
/ properties to modify it) and not the copy, you can detect any
changes.

This assumes, of course, that the class OtherClass implements Equals()
and is ICloneable. If it isn't then you'll have to do the "Equals"
comparison yourself in open code, and clone the object by constructing
a new one and setting its properties appropriately.
 
It sounds to me as though you understand everything I was saying. I'm
glad that I could be of help.

I have a homepage? Perhaps you're confusing me with Jon Skeet? :)
 
Bruce Wood said:
It sounds to me as though you understand everything I was saying. I'm
glad that I could be of help.

I have a homepage? Perhaps you're confusing me with Jon Skeet? :)

i glad that you could help me too! thank you a lot.
yes, i mixed you up with jon skeet ;)
 
Back
Top