.netTiers
Help Wanted! If you are using .netTiers and find it as invaluable as we do, please consider giving back to the .netTiers team by helping with our effort to fully document .netTiers. To help, simply create an account and you will then be able to edit this wiki.

Entity Layer

Modified: 11/18/2010 11:37 AM by mikiurban - Categorized as: Documentation

Edit

Entity Layer

Edit

What is an Entity?

An Entity is not a regular .net type, it is a significant type that holds an intrinsic meaning that is essential in your application. Entities can be real or conceptual and in business applications, which .netTiers is tailored to, holds a special meaning to the data. For example: an Employee, an Order and OrderDetail are all entities. Entities are malleable and have a lifecycle, and their types must take extra special checks and balances to ensure the integrity of the entity.

You can think of an Entity as the Reflection of a Database-table exposed in Object Oriented fashion. The Word Entity is the same which is commonly used and mostly for a Database-Table. So in the .Net environment an object reflecting a Database-table cascadingly, Exposing its Columns as class-Properties, Carefully matching the Data Types between a database-column and a .Net-Type(Let say string for varchar and Int16 for smallint).

Now think of a Database-Table 'USERS' where, definitely, each row of table is representing a single User's complete information(like her ID, Name, Age and Address) and on the other hand in .Net imagine an Object 'User' (with properties ID, Name, Age and Address). It actually is representing One User from database-table 'Users' or One Row of a database-table.

.netTiers' architecture provides us with an environment where we can Control the database entities (tables) by passing in these .Net entities in special methods. In fact those special methods which control these .Net entities are called "Controller Objects". We'll be studying about them in next articles. for now we should make sure that we know that we can call some dedicated methods from Controller objects to Retrieve an Entity or List of Entities. We can pass in an Entity into Controller behaviors to perform *CRUD actions.

  • CRUD::Create, Read, Update, Delete

Edit

A bit of history: The Entity Relationship Model

The entity first came to be known as the Entity Relation model, ERM. You can read the white paper that pretty much coined the term Entity and the entity life cycle. The Entity Relationship Model - Toward A Unified View of Data - By Dr. Peter Chen. This is significant because it was the first time there was a segregration in the way we made representations in a program from our data. These representations allows us to focus on creating a rich programmer experience with these valuable representations that we

Edit

What's your definition of an entity?

.netTiers uses the notion of the entity along with the TableModule & Data Transfer Object (DTO) Patterns in order to expose your database as entities. Meaning, for every table in your database, an entity will be generated for that table. The DTO allows you to pass the lightweight entities through the many tiers while still maintaining the loosely coupled open ended architecture of the Entity Layer, since it doesn't depend on any DataProvider.

.netTiers will also attempt to discover all of the relationships that your table has with other tables in the database and will create child properties of those relationships. This will build out your entire entity domain. Currently the relationship types supported are one to one, one to many, and many to many relationships. These relationships make it easy for you to intuitively work with your entities and now have a logical object graph. There are several ways to create a certain relationship, but we'll discuss the rules in the Database Model section.

Example: Customer Entity
///An example object graph of a customer entity looks like this.
/// Customer Parent
///   Order 1:1
///    OrderDetails //1:M
///    ProductCollection //1:M
///   CustomerDemographics //1:M
///   CustomerDemographicsCollection_From_CustomerCustomerDemo //M:M

Edit

EntityBase

The entities all inherit from two parent classes, the user class called EntityBase.cs which inherits from EntityBaseCore.generated.cs, the generated class. As mentioned earlier, every .generated class will be generated over and over again, do not modify these classes as your work will be lost when you regenerate your code.

These base classes implement the base behavior across all entities. The EntityBase class provides you with exclusive access to modify the behavior across all entities. You can override our default implementation and these changes will not get overwritten. This is a way for you to make changes and extend the behavior while at the same time, safeguarding your work.

EntityBase The EntityBase classes provide behavior to manage state using the EntityState property.



Edit

What is Entity State?

Entity State provides a way to track the current status of an entity in it's entity lifecycle, which differs from the CLR object lifecycle. There are 4 main EntityStates, found in the EntityState enumeration, Unchanged, Added, Changed, and Deleted. You do not have to manually keep track of state, when you modify a property, or create a new entity, or read an entity from the database .netTiers will automatically change the state and keep track for you.



1 /// <summary> 2 /// List of possible state for an entity. 3 /// </summary> 4 public enum EntityState 5 { 6 /// <summary> 7 /// Entity is read in from the database, unchanged 8 /// </summary> 9 Unchanged=0, 10 11 /// <summary> 12 /// Entity is new and not yet in the database 13 /// </summary> 14 Added=1, 15 16 /// <summary> 17 /// Entity has been modified 18 /// </summary> 19 Changed=2, 20 21 /// <summary> 22 /// Entity has been deleted 23 /// </summary> 24 Deleted=3 25 }




Edit

Entity LifeCycle

Assuming you have no data in your database, the very first thing you will do is add data to the database. In order to do this, you will have to create a new entity. Let's use the Customer entity that we've generated from the Northwind database, and create a new Customers entity and walk through the different states of the entity, which as mentioned earlier is different than the object lifecycle.

1 ///STAGE 1: Added 2 ///Create a new entity, whose EntityState is EntityState.Added 3 Customers customer = new Customers(); 4 customer.Address = "102 West Main Street"; 5 customer.City = "Atlantis"; 6 customer.Region = "Sea"; 7 customer.Phone = "230-555-0909"; 8 Response.Write(customer.EntityState); // EntityState.Added; 9 10 ///Persist 11 DataRepository.CustomersProvider.Save(customer); 12 13 14 ///STAGE 2: Unchanged 15 /// The EntityState has been set to EntityState.Unchanged 16 ///Once we persist the entity, it will refresh the entity from the database 17 ///If there is an identity column in your table that the entity represents 18 /// then the new identity of the inserted value is returned as well. 19 Response.Write(customer.CustomerID); 20 Response.Write(customer.EntityState); // EntityState.Unchanged; 21 22 23 ///STAGE 3: Changed 24 /// By modifying a property the entity will automatically 25 /// change state to an EntityState.Changed state. 26 customer.Region = "Under The Sea"; 27 Response.Write(customer.EntityState); // EntityState.Changed; 28 DataRepository.CustomersProvider.Save(customer); 29 30 31 ///STAGE 4: Deleted 32 /// Two ways exist being in an EntityState.Deleted state for an Entity. 33 /// MarkToDelete() method, or directly calling Delete in the repository. 34 /// MarkToDelete() is mainly used when using the Save() method, 35 /// wanting to delete an entity which aggregated 36 /// and part of a Collection, a TList<Entity>. 37 /// If you are working with a single entity as depicted, you would 38 /// just pass the entire entity into the DataRepository for Deletion. 39 40 ///Using Delete Method Directly on the Entity 41 DataRepository.CustomersProvider.Delete(customer); 42 43 ///Using Save Method in DataRepository with MarkToDelete() 44 customer.MarkToDelete(); 45 Response.Write(customer.EntityState); // EntityState.Deleted; 46 DataRepository.CustomersProvider.Save(customer); 47 48 ///EntityState.Unchanged 49 ///Say I want to delete all customers that have a city = Atlantis 50 /// Whenever you get any entity items from the Database, once created 51 /// the state is immediately changed to EntityState.Unchanged 52 TList<Customers> myList = DataRepository.CustomersProvider.GetByCity("Atlantis"); 53 54 for (int i = 0; i < myList.Count; i++) 55 { 56 Response.Write(myList[i].EntityState); // EntityState.Unchanged; 57 myList.RemoveEntity(myList[i]); 58 59 Response.Write(myList[i].EntityState); // EntityState.Deleted; 60 } 61 62 /// Now you've actually removed the entities from the list 63 Response.Write(myList.Count); // Prints 0 64 65 /// They are however moved to a DeletedItems collection 66 Response.Write(myList.DeletedItems.Count); //Prints 1 67 68 ///Will delete the items from the Database 69 DataRepository.CustomersProvider.Save(myList); 70 71 ///Or you can Iterate the list calling MarkToDelete(); 72 myList.ForEach( 73 delegate(Customers c) 74 { 75 c.MarkToDelete(); 76 } 77 ); 78 79 80 81 ///Will persist all of the Deleted entities. 82 DataRepository.CustomersProvider.Save(myList);




Edit

Base State Behavior

You can override the default behavior if you wanted and managed how EntityState was used. Perhaps if you wanted to use a StateMachine instead to manage state. Overall, it's a flexible approach that should let you customize however you need to..

There are also some entity state descriptor properties such as IsDeleted, IsDirty, IsNew. One other thing to note, is that you can remove the flag after using MarkToDelete by calling RemoveDeleteMark().

Excerpt from EntityBase.generated.cs

1 /// <summary> 2 /// True if object has been <see cref="MarkToDelete"/>. ReadOnly. 3 /// </summary> 4 [BrowsableAttribute(false), XmlIgnoreAttribute()] 5 public bool IsDeleted 6 { 7 get { return this.currentEntityState == EntityState.Deleted; } 8 } 9 10 11 /// <summary> 12 /// Indicates if the object has been modified from its original state. 13 /// </summary> 14 /// <remarks>True if object has been modified; otherwise False;</remarks> 15 [BrowsableAttribute(false), XmlIgnoreAttribute()] 16 public bool IsDirty 17 { 18 get 19 { 20 return this.currentEntityState != EntityState.Unchanged 21 && this.currentEntityState != EntityState.Added; 22 } 23 } 24 25 /// <summary> 26 /// Indicates if the object is new. 27 /// </summary> 28 /// <remarks>True if objectis new; otherwise False;</remarks> 29 [BrowsableAttribute(false), XmlIgnoreAttribute()] 30 public bool IsNew 31 { 32 get { return this.currentEntityState == EntityState.Added; } 33 set { this.currentEntityState = EntityState.Added; } 34 } 35 36 37 /// <summary> 38 /// Indicates state of object 39 /// </summary> 40 /// <remarks>0=Unchanged, 1=Added, 2=Changed</remarks> 41 [BrowsableAttribute(false), XmlIgnoreAttribute()] 42 public virtual EntityState EntityState 43 { 44 get { return this.currentEntityState; } 45 set { this.currentEntityState = value; } 46 } 47 48 49 /// <summary> 50 /// Accepts the changes made to this object. 51 /// </summary> 52 /// <remarks> 53 /// After calling this method <see cref="IsDirty"/> and <see cref="IsNew"/> are false. 54 /// <see cref="IsDeleted"/> flag remain unchanged as it is handled by the parent List. 55 /// </remarks> 56 public virtual void AcceptChanges() 57 { 58 this.bindingIsNew = false; 59 this.currentEntityState = EntityState.Unchanged; 60 OnPropertyChanged(string.Empty); 61 } 62 63 ///<summary> 64 /// Revert all changes and restore original values. 65 /// Currently not supported. 66 ///</summary> 67 /// <exception cref="NotSupportedException">This method throws exception.</exception> 68 public abstract void CancelChanges(); 69 70 ///<summary> 71 /// Marks entity to be deleted. 72 ///</summary> 73 public virtual void MarkToDelete() 74 { 75 if (this.currentEntityState != EntityState.Added) 76 this.currentEntityState = EntityState.Deleted; 77 } 78 79 80 ///<summary> 81 /// Remove the "isDeleted" mark from the entity. 82 ///</summary> 83 public virtual void RemoveDeleteMark() 84 { 85 if (this.currentEntityState != EntityState.Added) 86 { 87 this.currentEntityState = EntityState.Changed; 88 } 89 }




Edit

Interface Implementations

The entities themselves implement several interfaces to provide the full featured needs of consuming layers. The first two layers are custom .netTiers interfaces, the rest are from the System.ComponentModel and System.Runtime.Serialization namespaces.

Some of these interfaces are :

  • IEntityId - Gives exposure to an encapsulated primary key for your entity. Supports containment of composite primary keys.
  • IEntity- A .netTiers interface that provides all the functionality required for a .netTiers entity.
  • IComparable - Implements the ability to compare two entities types.
  • ICloneable - Implements the ability to clone an entity
  • IEditableObject - Implements the ability to commit or rollback changes to an object that is used as a datasource.
  • IComponent - Implements functionality required by all .Net System.ComponentModel Components.
  • INotifyPropertyChanged - Notifies subscribed clients that a property value has changed.
  • IDataErrorInfo - Provides the functionality to offer custom error information that a user interface can bind to.
  • IDeserializationCallback - Indicates that a class is to be notified when deserialization of the entire object graph has been completed.

Edit

What about generated views? Are they entities?

Generated views object types are not considered entities, although they share many similar attributes. View objects do not maintain state because they currently can not be persisted back into the database.



Edit

Entity Validation Rule Engine

One of the most powerful features that .netTiers provides to manage the integrity of your data is the Entity Rule Engine. This implements IDataErrorInfo in the EntityBase.generated.cs class. It provides the framework for managing entity business rules and custom error information that a user interface can bind to. Controls such as the DataGridView automatically detect this interface and provide error icons along with descriptions about the error.

There are several properties that assist you in managing your business rules. There are several built in validators ready to use out of the box.



  • NotNull - Determines the if the database column accepts null values.
  • StringMaxLength - Compares against the column width for the property.
  • StringRequired - Determines if the column allows empty string entries.
  • MaxWords - Determines whether the property has exceeted the maximum number of words
  • RegexIsMatch - Determines whether current property matches the regular expression
  • LessThanOrEqualToValue - Less than or equal to current value of property
  • LessThanValue - - Less than current value of property
  • EqualsValue - Equals current value of property
  • GreaterThanValue - Greater than current value of property
  • GreaterThanOrEqualToValue - Greater than or equal to current value of property
  • CompareValues - Compares values of T using a comparer
  • InRange - Ensures T is within a min and max of a Range using a Comparer.

However, we certainly understand that while those are all very useful, they do not cover the spectrum of potential business rules. The most important aspect of the rule engine is that all of the Validators are validated by a delegate which is called ValidationRuleHandler, through which you can set up using any ValidationRule, so long as it returns a bool value.

The target parameter is the object being validated, while e is a ValidationRuleArgs object that contains information about the rule (property to validate, error description). There are a couple of more properties that are of interest. There is now a property called IsValid that checks the rules to see if any have been broken. You can also get all of the broken rules through the BrokenRulesList property in your entity.

Validation/ValidationRuleHandler.cs

1 /// <summary> 2 /// Delegate providing method sig that will process validation rules. 3 /// </summary> 4 /// <remarks> 5 /// <para> 6 /// The method handler should set the Description attribute of the 7 /// <see cref="ValidationRuleArgs"/> parameter so that a meaningful 8 /// error is returned. 9 /// </para><para> 10 /// If the data is valid, the method must return true. If invalid, 11 /// the Description should be set the false should be returned. 12 /// </para> 13 /// </remarks> 14 public delegate bool ValidationRuleHandler(object target, ValidationRuleArgs e);


Edit

Example of Auto-Generated Rules

.netTiers will automatically detect the rules that apply for the database to maintain data integrity. However it's still extremely easy for you to add your own. Here's an example of automatically added rules for the Customer Entity we were working with.

1protected override void AddValidationRules() 2{ 3//Validation rules based on database schema. 4ValidationRules.AddRule(Validation.CommonRules.NotNull,"CustomerID"); 5 6ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 7 new Validation.CommonRules.MaxLengthRuleArgs("CustomerID",5)); 8 9ValidationRules.AddRule(Validation.CommonRules.NotNull,"CompanyName"); 10 11ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 12 new Validation.CommonRules.MaxLengthRuleArgs("CompanyName",40)); 13 14ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 15 new Validation.CommonRules.MaxLengthRuleArgs("ContactName",30)); 16 17ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 18 new Validation.CommonRules.MaxLengthRuleArgs("ContactTitle",30)); 19 20ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 21 new Validation.CommonRules.MaxLengthRuleArgs("Address",60)); 22 23ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 24 new Validation.CommonRules.MaxLengthRuleArgs("City",15)); 25 26ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 27 new Validation.CommonRules.MaxLengthRuleArgs("Region",15)); 28 29ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 30 new Validation.CommonRules.MaxLengthRuleArgs("PostalCode",10)); 31 32ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 33 new Validation.CommonRules.MaxLengthRuleArgs("Country",15)); 34 35ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 36 new Validation.CommonRules.MaxLengthRuleArgs("Phone",24)); 37 38ValidationRules.AddRule(Validation.CommonRules.StringMaxLength, 39 new Validation.CommonRules.MaxLengthRuleArgs("Fax",24)); 40 41}


Edit

That's great, but, how do I add my own rules?

Adding your own rules is easy. There are really several ways to do it since the properties are exposed. The easiest is perhaps to simply override the AddRules() method in your entities and add your own rules along with ones that were generated for you. Here's an example of the Orders entity from the Northwind generation.

Orders.cs -> The User customizable file for your entity class.

1/// <summary> 2/// Adds custom validation rules to this object. 3/// </summary> 4protected override void AddValidationRules() 5{ 6 base.AddValidationRules(); 7 8 //Add custom validation rules 9 ValidationRules.AddRule(Validation.CommonRules.StringRequired, "CustomerID"); 10 11 ValidationRules.AddRule(Validation.CommonRules.GreaterThanOrEqualToValue<Decimal?>, new Validation.CommonRules.CompareValueRuleArgs<Decimal?> ("Freight", 0)); 12 13 ValidationRules.AddRule( 14 Validation.CommonRules.LessThanOrEqualToValue<Decimal?>, 15 new Validation.CommonRules.CompareValueRuleArgs<Decimal?>( 16 "Freight", 200)); 17 18 19 ValidationRules.AddRule(ValidateOrderDate, "OrderDate"); 20} 21 22 23/// <summary> 24/// Validates the order date. 25/// </summary> 26/// <param name="target">The target.</param> 27/// <param name="e">The e.</param> 28/// <returns></returns> 29private bool ValidateOrderDate(object target, Validation.ValidationRuleArgs e) 30{ 31 if ((this.OrderDate ?? DateTime.MinValue) > DateTime.Today) 32 { 33 e.Description = "The Order Date must not be in the future."; 34 return false; 35 } 36 37 return true; 38}


Edit

So, how do I validate and see the error message?

The easiest way to validate is when using a single entity is just to call the IsValid property. It will automatically trigger the validation process. You can also force the validation process by calling Validate();



1 Orders o = new Orders(); 2 o.OrderDate = new DateTime(2001, 8, 29); 3 o.ShipAddress = "302 West Main Street"; 4 o.ShipCity = "Atlantis"; 5 o.ShipCountry = "Anywhere"; 6 o.ShipName = "Frank Sanders"; 7 o.ShipPostalCode = "55512"; 8 o.ShipRegion = "Under the Sea"; 9 10 11 o.Validate(); 12 ///Error property is a newline delimeted list of your broken rules. 13 if (!o.IsValid) 14 lblMessage.Text = o.Error; 15 16 17 18 ///you can actually access all of the rules that were broken on the entity. 19 foreach(BrokenRule rule in o.BrokenRulesList) 20 { 21 lblMessage.Text = string.Format("<li>{0} - {1}</li>", 22 rule.Property, rule.Description); 23 } 24 25 /// Suppose we have a partner vendor that 26 /// processes orders for us, and we need 27 /// to validate all of today's orders. 28 /// Get today's orders and validate them. 29 TList<Orders> ordersList = GetOrdersFromVender(); 30 if (!ordersList.IsValid) 31 { 32 StringBuilder sb = new StringBuilder(); 33 sb.Append("<li>"); 34 foreach(Orders o in ordersList.InvalidItems) 35 { 36 sb.Append(o.Error.Replace("\n", "<li>")); 37 } 38 lblMessage.Text = sb.ToString(); 39 40 }




Overall, the important thing to remember is that since the Rules engine uses delegates, your logic can live any place you would like it to. There will be more coverage with complex business processes and validation in the Component Layer chapter.

Edit

Using Collections in .netTiers, TList & VList:

.netTiers has two generic lists that it exclusively uses for your entities. TList and VList. The TList is the most full featured and only works with Types that implement IEntity, which are entities that are generated from a table as formerly stated. VList is a list for limited View Entities that don't maintain EntityState.

1 Orders order = new Orders(); 2 order.OrderDate = new DateTime(2001, 8, 29); 3 order.ShipAddress = "302 West Main Street"; 4 order.ShipCity = "Atlantis"; 5 order.ShipCountry = "Anywhere"; 6 order.ShipName = "Frank Sanders"; 7 order.ShipPostalCode = "55512"; 8 order.ShipRegion = "Under the Sea"; 9 10 ///Index Of, Get's the location of the order in the list 11 int index = ordersList.IndexOf(order); 12 13 ///FindIndex 14 ///Returns the integer value if 15 ///one of the criteria matches your predicate 16 ordersList.FindIndex( 17 delegate(Orders orders) 18 { 19 return orders.RequiredDate < DateTime.Today.AddDays(2); 20 }); 21 22 23 ///Insert 24 ///Useful if you want to insert an order in a specific location 25 if (index < 0) 26 ordersList.Insert(0, order); 27 28 ///Add 29 ///Appends an order to the list 30 ordersList.Add(order); 31 32 33 ///AddNew 34 ///Appends a new order to the list 35 ordersList.AddNew(); 36 ordersList[ordersList.Count - 1].OrderDate = DateTime.Today; 37 38 39 ///RemoveEntity 40 ///Removes the order from the list and places it in DeletedItems 41 ordersList.RemoveEntity(order); 42 43 ///RemoveAt 44 ///Removes the first entry of the list 45 ordersList.RemoveAt(0); 46 47 ///RemoveAt 48 ///Removes the entity where it exists 49 ordersList.Remove(order); 50 51 ///ListChanged 52 ///Fires an event when the list has changed 53 ordersList.ListChanged += 54 new System.ComponentModel.ListChangedEventHandler(ordersList_ListChanged); 55 56 57 ///IsDeletedCount 58 ///Returns the count of the DeletedItems Collection 59 int deletedCount = ordersList.IsDeletedCount; 60 Debug.Assert(deletedCount == ordersList.DeletedItems.Count); 61 62 ///IsDirtyCount 63 ///Returns the count of the items that have an 64 ///EntityState == EntityState.Changed 65 int dirtyCount = ordersList.IsDirtyCount; 66 Response.Write(string.Format("You have modified {0} entities.",dirtyCount)); 67 68 ///IsNewCount 69 ///Returns the count of the items that have an 70 ///EntityState == EntityState.Added 71 int newCount = ordersList.IsNewCount; 72 Response.Write(string.Format("You have added {0} entities.", newCount)); 73 74 ///FindAllBy 75 ///Returns a new List of Entities that 76 /// match the FindAllByType 77 ///FindAllByType.Contains, FindAllBy.StartsWith, FindAllByType.EndsWith 78 TList<Orders> sList = ordersList.FindAllBy(TList<Orders>.FindAllByType.StartsWith, 79 OrdersColumn.ShipCity, "Atl"); 80 81 TList<Orders> cList = ordersList.FindAllBy(TList<Orders>.FindAllByType.Contains, 82 OrdersColumn.ShipCity, "ant"); 83 84 TList<Orders> eList =ordersList.FindAllBy(TList<Orders>.FindAllByType.EndsWith, 85 OrdersColumn.ShipCity, "tis"); 86 87 ///FindAll 88 ///Returns a new List of Entities that match using the Table Enum Columns 89 TList<Orders> eqList = 90 ordersList.FindAll(OrdersColumn.ShipCity, "Atlantis"); 91 92 93 ///FindAll 94 ///Returns a new List of Entities using a predicate 95 TList<Orders> eqList2 = ordersList.FindAll( 96 delegate(Orders o2){ 97 return 98 o2.OrderDetailsCollection.Count > 0 && 99 o2.OrderDate == DateTime.Today; 100 }); 101 102 ///Exists 103 ///Returns a bool if one of the criteria matches your predicate 104 if (ordersList.Exists( 105 delegate(Orders o3) 106 { 107 return 108 o3.OrderDetailsCollection.Count > 0 && 109 o3.OrderDate == DateTime.Today; 110 })) 111 { 112 Response.Write("There are orders today"); 113 } 114 115 ///ToArray 116 ///Creates an orders array from a list 117 Orders[] orderArray = ordersList.ToArray(); 118 119 ///ToDataSet 120 ///Creates a DataSet with children relationships from your TList. 121 DataSet ds = ordersList.ToDataSet(true); 122 123 /// Filter as a string 124 /// Creates a view inside of your list using a case sensitive filter 125 /// Great for cached items that you need to show 126 /// different sets of entities based on criteria. 127 ordersList.Filter = "ShipCity = 'Atlantis'"; 128 ordersList.ApplyFilter(); 129 ordersList.ForEach( 130 delegate(Orders filteredOrder) 131 { 132 Debug.Assert(filteredOrder.ShipCity == "Atlantis"); 133 }); 134 135 ///To Remove the filter, you simply call ResetFilter; 136 ordersList.RemoveFilter(); 137 138 /// Filter using a Predicate delegate 139 /// Great for needing to filter on items that 140 /// different sets of entities based on criteria. 141 ordersList.ApplyFilter(GetValidAtlantisOrders); 142 ordersList.ForEach( 143 delegate(Orders filteredOrder) 144 { 145 Debug.Assert(filteredOrder.IsValid 146 && filteredOrder.ShipCity == "Atlantis"); 147 }); 148 149}//End Page_Load 150 151 152 /// <summary> 153 /// Gets the valid atlantis orders. 154 /// </summary> 155 /// <param name="o">The o.</param> 156 /// <returns></returns> 157 public bool GetValidAtlantisOrders(Orders o) 158 { 159 return (o.IsValid 160 && o.ShipCity == "Atlantis" 161 && o.OrderDetailsCollection.Count > 0 162 && o.OrderDetailsCollection.IsValid); 163 } 164 165 void ordersList_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e) 166 { 167 throw new Exception("The method or operation is not implemented."); 168 } 169 170 /// <summary> 171 /// Gets the orders from vendor. Stub method, does nothing. 172 /// </summary> 173 /// <returns></returns> 174 public TList <Orders> GetOrdersFromVendor() 175 { 176 //Get Some orders from a vendor 177 return new TList<Orders>(); 178 } 179}


Edit

Entity Management Framework:

In any application there are often several aspects of your application that you commonly have to do in order to optimize your application.

Edit

EntityFactoryBase

The EntityFactoryBase is a creational construct that exists to assist the creation of entities of an unknown type at runtime. Entities are/were normally created in the DataRepository in a given EntityProvider's Fill method. So if I had DataRepository.MyEntityProvider, there would be a method called Fill that took an IDataReader, an TList (EntityCollection) and a row params. This method is actually going to hydrate the entities when coming back from the DataRepository.

This version of the templates allow you to create component business objects which inherit from the entity objects. Since these component objects live in the tier on top of the Data Access Layer and Entities. Since the DataRepository creates entities for usage, it's not possible to create those types because the DAL doesn't know about the smart component business objects, only the Entity DTO objects. The role the EntityFactory is used for is you have the ability to define which factory will be used to create your objects to be filled in the app/web.config.

Example:

1entityFactoryType="Northwind.Entities.EntityFactory"; 2// OR 3entityFactoryType="Northwind.Entities.ComponentEntityFactory";


Each factory will use the namespace of the factory to create unknown types at runtime using an Activator. This type discovery is cached and so you only face a perf hit once.

There are events that you can subscribe to during this process to inject some logic before the object is created and just after it's created but before being hydrated. This is useful if you wanted to attach your own events to the entity.

Edit

EntityCache

The EntityCache class manages the lifetime of entities that you would like to not have to be queried for all the time. In reality, this class simply wraps the Enterprise Library Cache. EntLib offers a full featured and configurable object cache. The entity cache can be used by any object, and does not have to be an entity. More info can be found here: Enterprise Library Caching Block

You don't "Have" to configure the cache to work, .netTiers will generate a default cache configuration at runtime if one does not exist, but it's recommended that you do create a configuration for your caching block to optimize the cache settings for your application. The entity cache can easily be configured by pointing your Enterprise Library Configurator tool at your app/web.config. We've also recently started including a sample default settings entlib.config in the MyNamespace.UnitTest project.

Edit

IEntityCacheItem

When this marker interface is applied to an entity, the entity will automatically be placed into cache. The interface provides lifetime and callback parameters used to manage the caching of your entities. This is an interface that you would have to apply yourself to the entity at the concrete class level.

Edit

EntityLocator

The EntityLocator sits on top of the Locator class of the Microsoft Patterns and Practices Group's ObjectBuilder Framework. The locator is responsible for creating a WeakReference'd Object Store so that as your application is handling a high volume of entities, which many are of the same record, we will return to you the same object for all references until that entity is persisted to the DataRepository. Combining this feature with Optimistic Concurrency with a Timestamp on your Table, you'll end up saving quite a bit on memory consumption. And for those that might not know, a weak reference means that the objects will still be garbage collected as soon as there are no more actual references to that entity any longer.

This feature has to be enabled in the app/web.config under enableEntityTracking="true/false"

Edit

EntityManager

The EntityManager is the glue that holds it all together, and should be considered the entry point to most of these features, with the exception of the EntityCache. When an object is about to be created, and DataRepository.Provider.EntityTracking is enabled, the EntityManager get's called. The EntityManager contains a single EntityLocator object and a collection of EntityCache objects, for all of your different entity cache providers. Most likely though, there will only be a single EntityCache object in there.

The EntityManager contains a LocateOrCreate method that determine if an entity already exists and is currently being referenced, if so, then return that entity, otherwise, create a new one using the entity factory defined and begin tracking the entity.

There are several yet to be implemented features which we have in mind for the EntityManager such as managing meta data amongst the entities and being able to determine relationship boundaries at runtime.

ScrewTurn Wiki version 2.0.31.