- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Somwewhat automated delete functionality for databinding
Joined: 26-Feb-2006
Hi,
I have read most of the posts regarding the logic behind not including automatic delete functionality into EntityCollection.
I understand the reasons, but yet would like to automate some of the functionality for myself.
So, I came up with some code derived from EntityCollection that keeps track of the deleted entities.
I am positive this technique would work, but I have a few questions: 1) Why is my EntityCollection derived class not showing any of the entity factories in the design-time drop-down? What can I do to make this have the same design-time functionality as EntityCollection? 2) Are there some major architectural reasons as to why not to use this technique? 3) As the 2.0 release nearing, I am relatively sure you know at this point whether you will include this type of functionality out of the box. Can you please let us know?
using System; using System.Collections; using System.ComponentModel; using System.Runtime.Serialization; using System.Xml;
using JetHavenLLBLData.EntityClasses; using JetHavenLLBLData.HelperClasses;
using SD.LLBLGen.Pro.ORMSupportClasses;
namespace JetHavenData {
[Serializable]
public partial class JetHavenCollection : EntityCollection
{
private EntityCollection _deletedEntities = new EntityCollection();
public EntityCollection DeletedEntities
{
get { return _deletedEntities; }
}
public JetHavenCollection():base()
{
this.BeforeRemove += new EventHandler(JetHavenCollection_BeforeRemove);
}
void JetHavenCollection_BeforeRemove(object sender, EventArgs e)
{
_deletedEntities.Add(sender as IEntity2);
}
public EntityCollection DirtyEntities
{
get
{
EntityCollection ec = new EntityCollection(this.EntityFactoryToUse);
foreach (EntityBase2 de in this.DirtyEntities)
ec.Add(de);
return ec;
}
}
public void ClearDeletedEntities()
{
_deletedEntities.Clear();
}
public JetHavenCollection(IEntityFactory2 entityFactoryToUse):base(entityFactoryToUse)
{
}
public JetHavenCollection(IEntityFactory2 entityFactoryToUse, IValidator validatorToUse):base(entityFactoryToUse, validatorToUse)
{
}
protected JetHavenCollection(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
tolga wrote:
Hi,
I have read most of the posts regarding the logic behind not including automatic delete functionality into EntityCollection.
I understand the reasons, but yet would like to automate some of the functionality for myself.
So, I came up with some code derived from EntityCollection that keeps track of the deleted entities.
I am positive this technique would work, but I have a few questions: 1) Why is my EntityCollection derived class not showing any of the entity factories in the design-time drop-down? What can I do to make this have the same design-time functionality as EntityCollection?
The code in the toolboxitem is pretty limited, as vs.net 2002/3 doesn't offer rich type retrieval. This means that the toolboxitem scans the assembly in which the entitycollection class is in (or better: the type the toolboxitem is associated with, which is normally the generated entitycollection class) for IEntityFactory2 implementations.
So it's best to add your own entitycollection derived class to the assembly with the generated code.
2) Are there some major architectural reasons as to why not to use this technique?
automatic deletes? It has serious drawbacks, but I understand you learned them while reading the threads about this on the forum?
3) As the 2.0 release nearing, I am relatively sure you know at this point whether you will include this type of functionality out of the box. Can you please let us know?
This won't be added to v2 and likely also not beyond that version, as it's a fundamental problem which has a solution in the Unitofwork.
Joined: 26-Feb-2006
But you could add a internal collection to EntityCollection to keep track of deleted entities.
There could be a method to clear this internal collection. So the user can start a new state by clearing the deletedentities collection and then at some point get the deletedentities collection to call the DataAccessAdapter.DeleteEntityCollection method.
This way, you're not giving the user the ability to automatically deleted the deletedentities from the database. You're just providing a convenience mechanism to keep track of deletedentities with which the user can do whatever they want...
I believe this is similar to whoever proposed the MarkAsDeleted functionality in another post, except it adds the functionality of keeping track of the deletedentities from a winform GUI perspective...
Thanks,
Tolga
This is the following code I have turned EntityCollection into because it really saves a lot of work:
/////////////////////////////////////////////////////////////// // This is generated code. If you modify this code, be aware // of the fact that when you re-generate the code, your changes // are lost. If you want to keep your changes, make this file read-only // when you have finished your changes, however it is recommended that // you inherit from this class to extend the functionality of this generated // class or you modify / extend the templates used to generate this code. ////////////////////////////////////////////////////////////// // Code is generated using LLBLGen Pro version: 1.0.2005.1 // Code is generated on: Sunday, February 26, 2006 2:20:15 PM // Code is generated using templates: C# template set for SqlServer (1.0.2005.1) with Web Serice support. // Templates vendor: Solutions Design. // Templates version: 1.0.2005.1.102305 ////////////////////////////////////////////////////////////// using System; using System.Collections; using System.ComponentModel; using System.Runtime.Serialization; using System.Xml;
using JetHavenLLBLData.EntityClasses;
using SD.LLBLGen.Pro.ORMSupportClasses;
namespace JetHavenLLBLData.HelperClasses {
// __LLBLGENPRO_USER_CODE_REGION_START AdditionalNamespaces
// __LLBLGENPRO_USER_CODE_REGION_END
/// <summary>
/// Generic Collection class for storing collections of entities of the same type.
/// </summary>
[Serializable]
public partial class EntityCollection : EntityCollectionBase2
{
private ArrayList _deletedEntities = new ArrayList();
public EntityCollection DeletedEntities
{
get
{
EntityCollection foo = new EntityCollection();
foreach (EntityBase2 e in _deletedEntities)
foo.Add(e);
return foo;
}
}
/// <summary>
/// CTor
/// </summary>
public EntityCollection():base()
{
this.BeforeRemove += new EventHandler(EntityCollection_BeforeRemove);
}
/// <summary>
/// CTor
/// </summary>
/// <param name="entityFactoryToUse">The entity factory object to use when this collection has to construct new objects.
/// This is the case when the collection is bound to a grid-like control for example.</param>
public EntityCollection(IEntityFactory2 entityFactoryToUse):base(entityFactoryToUse)
{
this.BeforeRemove += new EventHandler(EntityCollection_BeforeRemove);
}
/// <summary>
/// CTor
/// </summary>
/// <param name="entityFactoryToUse">The entity factory object to use when this collection has to construct new objects.
/// This is the case when the collection is bound to a grid-like control for example.</param>
/// <param name="validatorToUse">The validator object to use for new entities constructed using the entity factory. Ignored when null</param>
public EntityCollection(IEntityFactory2 entityFactoryToUse, IValidator validatorToUse):base(entityFactoryToUse, validatorToUse)
{
this.BeforeRemove += new EventHandler(EntityCollection_BeforeRemove);
}
/// <summary>
/// Protected CTor for deserialization
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected EntityCollection(SerializationInfo info, StreamingContext context) : base(info, context)
{
this.BeforeRemove += new EventHandler(EntityCollection_BeforeRemove);
}
void EntityCollection_BeforeRemove(object sender, EventArgs e)
{
_deletedEntities.Add(sender as IEntity2);
}
public EntityCollection DirtyEntities2
{
get
{
EntityCollection ec = new EntityCollection(this.EntityFactoryToUse);
foreach (EntityBase2 de in this.DirtyEntities)
ec.Add(de);
return ec;
}
}
public void ClearDeletedEntities()
{
_deletedEntities.Clear();
}
/// <summary>
/// ITypedList.GetItemProperties implementation. Necessary for Complex databinding.
/// </summary>
/// <param name="listAccessors">Data to determine which property descriptor set to create</param>
/// <returns>collection of property descriptors which will be used to create property related objects, like columns in a bound grid.</returns>
public override PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
// determine the type of the entity to return the properties of.
if((listAccessors==null)||listAccessors.Length==0)
{
// this collection is bound to the control, simply call the base class routine to create property descriptors.
return base.GetItemProperties(listAccessors);
}
// use the last entry in the listAccessors, grab its TypeContainedAttribute and instantiate an instance of the type in that attribute,
// use that entity instance to produce properties.
if CF
object[] customAttributes = listAccessors[listAccessors.Length-1].ComponentType.GetCustomAttributes(typeof(TypeContainedAttribute), false);
TypeContainedAttribute typeAttribute = null;
if(customAttributes.Length>0)
{
typeAttribute = (TypeContainedAttribute)customAttributes[0];
}
else
TypeContainedAttribute typeAttribute = (TypeContainedAttribute) listAccessors[listAccessors.Length-1].Attributes[typeof(TypeContainedAttribute)];
endif
if(typeAttribute==null)
{
// not found, not specified, can't determine property descriptors.
return new PropertyDescriptorCollection(null);
}
// create instance
IEntity2 newInstance = (IEntity2)Activator.CreateInstance(typeAttribute.TypeContainedInCollection);
// create property descriptors.
if(base.Site==null)
{
return base.GetPropertyDescriptors(newInstance, typeAttribute.TypeContainedInCollection);
}
else
{
// in design mode. Because we ended up here, listAccessors is at least of length 1. Don't include collection properties.
return base.GetPropertyDescriptors(newInstance, typeAttribute.TypeContainedInCollection, true);
}
}
#region Custom EntityCollection code
// __LLBLGENPRO_USER_CODE_REGION_START CustomEntityCollectionCode
// __LLBLGENPRO_USER_CODE_REGION_END
#endregion
#region Included Code
#endregion
}
}
Joined: 12-Feb-2004
Well instead of maintaining the deleted collection and dirty collection you could add them to the unit of work marked with being deleted or saved. Then you could commit this unit of work when the user is completed or not and leave everything the way it is. Then you don't have two collections and the unit of work will take care of which operations must happen first when call the commit.
Take a look under the Unit of Work section of the manual for some good examples and more in depth explanation.
// add the customer for a recursive save action.
uow.AddForSave(newCustomer, true);
// add this product for deletion.
uow.AddForDelete(productToDelete);
// commit all actions in one go
uow.Commit(adapter, true);