Sunday, November 13, 2011

Using EF 4.1 in Web Applications



Scenario - Internet Applications being stateless in nature, how to use the Entity Framework in n-Tier ASP.NET Applications.

Challenge - The biggest challenge of using EF in web applications is - the short lived life cycle of a web page prevents entities from remaining attached to an ObjectContext and providing the required state information of these entities to SaveChanges for updates. While it works fine in scenarios where the Page instantiates an instance of ObjectContext, do the Insert/Update/Delete operations and call the SaveChanges in the same request. At the end of the request, the Page is disposed along with the dependent objects.

But it fails in scenarios where the user makes a series of updates in several requests and finally commit the save operation.

It's easiest to make a call to SaveChanges when you have a long-running ObjectContext that is not an option in the web scenario.

Without the long-running context, there are two possible paths to take.

The first involves persisting the entities in memory on the server-most likely in the user's session. When the user wants to update you can attach those entities to a new context and update them using the new values coming from the controls on the page, then call SaveChanges The downside is scalability when your user base grows.

The second path for allowing SaveChanges to do its job would entail performing the query again prior to saving. You can then update the newly queried entities with the values coming from the client. The state information of entities are supplied from the application logic.

We have taken the second path. Here how we achieved this through coding.

DB Design -
DB Desing


CRUD Operations

public void InsertUpdateTemplate(Template template)
{
using (SampleDBEntities db = new SampleDBEntities (this.EFConnectionString))
{
if (template.Added)
{
db.Templates.Add(template);
}
else
{
var templateEntity = db.Templates.Find(template.TemplateId);
db.Entry(templateEntity).CurrentValues.SetValues(template);
db.Entry(templateEntity).State = template.State;

var fixedDeposites = db.FixedDeposites;
foreach (FixedDeposite deposite in template.FixedDeposites.Where(i => i.State != EntityState.Unchanged))
{
if (deposite.Added)
{
db.Entry(deposite).State = EntityState.Added;
}
else
{
var entity = fixedDeposites.Find(deposite.FixedDepositeId);
db.Entry(entity).CurrentValues.SetValues(deposite);
db.Entry(entity).State = deposite.State;
}
}

var accounts = db.SavingAccounts;
foreach (SavingAccount account in template.SavingAccounts.Where(i => i.State != EntityState.Unchanged))
{
if (account.Added)
{
db.Entry(account).State = EntityState.Added;
}
else
{
var entity = accounts.Find(account.SavingAccountId);
db.Entry(entity).CurrentValues.SetValues(account);
db.Entry(entity).State = account.State;
}
}
}

db.SaveChanges();
}
}

Where :

[MetadataType(typeof(TemplateMetadata))]
public partial class Template : BaseEntity, IValidatableObject
{
}

public class TemplateMetadata
{
//Place for applying Data Annotations on EF generated class.
[Required(ErrorMessage = "Template must have a name")]
public string Name { get; set; }
}

where:

Model Metadata
ASP.NET MVC 2 introduced an extensible model metadata system where developers could implement a class which derived from ModelMetadataProvider to provide meta-information about the models in the system. In ASP.NET MVC 3, You can find the metadata provider findable via the dependency resolver. This is place to apply data annotations on EF generated classes.


public abstract class BaseEntity
{
public abstract bool Added { get; }
public bool Modified { get; set; }
public bool Deleted { get; set; }

public EntityState State
{
get
{
if (this.Added)
{
return EntityState.Added;
}
else if (this.Modified)
{
return EntityState.Modified;
}
else if (this.Deleted)
{
return EntityState.Deleted;
}
return EntityState.Unchanged;
}
}
}


References : http://msdn.microsoft.com/en-us/library/orm-9780596520281-01-21.aspx

No comments:

Post a Comment