I am still a "trial period" user and I am probably trying to use ES to its extreme capability, but all I ask is that my comments are, at least, used to consider ES going forward.
What I have found, or my impressions: IT seems to me that several features were implemented within ES templates because they are so common, or simply desired by most users. I also believe that some features are implemented because its hard to imagine that they could conflict with any particular framework design. I ask for VERY careful consideration on this point.
There are many ways to achieve a task, or to create a framework design and -yes - some frameworks have features in common.
Take for example, INotifyPropertyChanged; this was implemented on the "core" library for ES. It might seem that all users would want this implememented and it might seem that it would not be a factir for those who do not.
Now consider my scenario:
1. INotifyPropertyChanged (Using ES & WCF in an n-tier framework): For me, INotifyPropertyChanged only applies to a UI. I do not have any business logic that seeks to register with PropertyChanged events. Thus, the interface INotifyPropertyChanged, for me, ONLY applies to the UI tier. When a user makes a change in the UI to one control, INotifyPropertyChanged is used for other controls to auto-update. However, the client-side is where the UI code resides, not the ES EntityBase classes where the interfaces are currently implemented.
2. PropertyChanges: It is required for my model that properties are not considered changed if the same value is applied. I must also not allow a user to make a change, change the value back to the original (which would normally make an object be marked a changed) and save the data with the same values. To achieve this, my ProxyStub classes implement a custom Getter for every property and I have a custom base class for the client ProxyStubs. This allows catching property changes and disabling the Svae button which no changes are applied. The client-side holds a copy of original values and rejects saving if all values match original values... the service-side then redundantly performs the same check in case the client-side is somehow compromised.
My ProxyStub properties are defined like this:
[
DataMember]
public System.DateTime? Created {
get { return _Created; }
set { SetPropertyValue<System.DateTime?>("Created", ref this._Created, value); }
}
private System.DateTime? _Created;
3. IDataErrorInfo is the interface Microsoft uses to have business bjects automatically update the UI with an Error Icon. The problem is that On/Off, Pass/Fail notification is inadequate; there are requirements for error levels. Further, again, the ProxyStub classes inertact with the UI, not the core EntityBase classes. So, again the ProxyStubs must be customized and the core classes have uneeded overhead.
4. Interfaces: My business logic tier interacts with interfaces, not implementations. When ES reads the tables within the database, I have it create copy constructors for my ProxyStub classes ... AND... I have the EntityBase classes also implement the interface as well to create copy constructors and methods.
Here is a sample:
[DataContract(Namespace = "http://mynamespace.com/", Name = "AccountingPeriod")]
[XmlType(TypeName = "AccountingPeriodProxyStub")]
[Serializable]
public partial class AccountingPeriodProxyStub : ClientBase, IAccountingPeriod {
public AccountingPeriodProxyStub(){
}
public AccountingPeriodProxyStub(IAccountingPeriod copyObject){
SetValuesFromCopy(copyObject);
}
public void SetValuesFromCopy(IAccountingPeriod copyObject){
this._GCRecord = copyObject.GCRecord;
this._Oid = copyObject.Oid;
this._Created = copyObject.Created;
this._Modified = copyObject.Modified;
this._Name = copyObject.Name;
this._Description = copyObject.Description;
this._AccountingPeriodNumber = copyObject.AccountingPeriodNumber;
this._FromDate = copyObject.FromDate;
this._ThruDate = copyObject.ThruDate;
this._InternalOrganization = copyObject.InternalOrganization;
this._PeriodType = copyObject.PeriodType;
this._OptimisticLockField = copyObject.OptimisticLockField;
}
So, what am I really getting at? Why did I list so many samples?
What I am trying to make clear is that many users are likley to be like me where they need exacting control over their class definitions. This means we WILL be modifying the templates extensively.
MY SUGGESTIONS:
CORE LIBRARIES SHOULD STICK TO PERSISTENCE ONLY FEATURES: INotfyPropertyChanged and other UI related features, or any features not directly related to persistence should be moved into templates and out of the core library. This will offer the most protection from introducing breaking changes and will offer the most flexibility for customers to implement their particular design features.
NEVER OVERWRITE TEMPLATES: Consider what can be done to make using customized templates as painless as possible. In my opinion, it is disastrous for an upgrade to overwrite anything that may have been customized. I cannot imagine how horrific it would be to have templates overwritten by mistake. I might suggest that the "default" templates be kept in a separate and unused directory and that a tool is created to regenerate (copy back) default templates. Templates should not be overwritten in an upgrade.
PROVIDE MULTIPLE TEMPLATES: I suggest having multiple templates ranging from minimal (include only persistence related features that are required, no INotifyPropertyChanged, No base classes, no IDataErrorInfo, etc.) to a host of optional "starting" templates. I believe this allows for the easiest comparison of changes between versions. It means that users could most easily find ES persistence related changes. Now, features for INotifyPropertychanged, IDataErrorInfo, ProxyStubs, Custom Base classes, etc. are implmented in starting templates.
NOTE: MyGeneration needs some changes (IMO) that I belive ES should request.
1. Its nice to have forms that offer various options for code generation; however, the selected "options" are not persisted. It is simply annoying to reset the options every time. I would prefer to hand modify an option rather than have a popup form that doesn't remeber my settings. Essentially, that is what I do now - hand modify, but its a pain because there is no central location to easily apply settings.
2. If you look at the code generation, current options are specific to particular templates. It seems really apparent to me that there should be globally applied template options where "bricks" of code could be applied. For example, using a base class. Desiring a base class is common, it seems it could be applied to numerous templates. Why have to manually define this feature for every template. If there were global template options, they could be selected/deselected for any template. Of course, persisting the settings as I mentioned above is really crucial. It would be best if settings could be loaded/unloaded and a default for each template applied.
Anyway, I am a "rooky" with ES and MyGeneration, but these are my thoughts that I hope they are at least considered.