ict.ken.be

Delivering solid user friendly software solutions since the dawn of time.

Entity Framework 4.1 DbContext Data Access - Notes

Categories: EF Notes

Entity Framework 4.1 DbContext Data Access
Julie Lerman

1. DbContext
  • .Add
  • .Attach is not an update but tells EF to track the entity.
  • .Remove
  • .Entry.State=Modified Added Deleted
var newPerson = context.People.Add(new Person { Name = "Julie"});
Assert.IsTrue(context.Entry(newPerson).State==System.Data.EnitityState.Added);
 
//context.Aliases.Attach(existingAlias); //line below willl do implicit
context.Entry(existingAlias).State = System.Data.EntityState.Modified;
Assert.IsTrue(context.Entry(exisitingAlias).State == System.Data.EntityState.Modified);
 
var query = from p in context.Person where p.Id == 3 select p;
var person = query.FirstOrDefault();
//use instead ->
var person = context.People.Find(3); //uses context cach as a bonus
 
//objects managed by the cache
ObservableCollection<Person> = context.People.Local 
Proxies, Change Tracking & Lazy Loading
[TestMethod]
public void ObjectsGetDynamicProxies()
{
var context = new TwitterContext();
var alias = context.Aliases.FirstOrDefault();
Assert.IsTrue(alias.GetType().FullName.StartsWith("System.Data.Entity.DynamicProxies"));
}
 
[TestMethod]
public void ObjectsAreInstantlyChangeTracked()
{
var context = new TwitterContext();
var alias = context.Aliases.FirstOrDefault();
alias.Name = "abcde";
//context.ChangeTracker.DetectChanges(); when not using dynamic proxy
Assert.IsTrue(((context as IObjectContextAdapter).ObjectContext).ObjectStateManager.GetObjectStateEntries(EntityState.Modified).Count() == 1);
}
 
public class Alias
{
public virtual int AuthorKey { get; set; } //will create lazy loading dynamic proxy
public virtual ICollection<Tweet> Tweets { get; set; } //one marked as virtual will enable lazy loading
public string Email { get; set; } //must be virual if you want change tracking
public string AliasPlusName //no setter so will be skipped
{
get { return Name + "(" + UserName + ")"; }
}
}
Change Tracker
  • DetectChanges called by:
  • DbSet .Find .Local .Remove .Add .Attach
  • DbContext .SaveChanges .GetValidationErrors .Entry
  • DbChangeTracker.Entries
//if you do NOT want DetectChanges to get called
context.Configuration.AutoDetectChangesEnabled = false;
Get To ObjectContext
  • var oContext = (myDbContext as ObjectContextAdapter).ObjectContext;
  • Linq to Entities CompiledQuery: No DbContext, No Adapter.ObjectContext
  • EF5 : http://blogs.msdn.com/b/stuartleeks/archive/2012/06/12/entity-framework-5-controlling-automatic-query-compilation.aspx
[TestMethod]
public void CanGetDatabaseValuesFromEntry()
{
var context = new TwitterContext();
var alias = context.Aliases.FirstOrDefault();
DbPropertyValues dbValues = context.Entry(alias).GetDatabaseValues();
Assert.IsNotNull(dbValues);
}
 
//when savechanges and an optimistic concurrency error was thrown
var entry = context.Entry(alias);
entry.OriginalValues.SetValues(entry.GetDatabaseValues()); //client win
entry.Reload(); //or use for server win
From existing database
  • edmx file -> DbContext T4 Template -> Simple POCO Classes and DbContext
  • ADO.Net DbContext Generation 
2. Code First Database Initialization
  • Connectionstring Available (else use buildstring) -> Database Exists (else create database) -> Use Database
  • Buildstring: SQL Server Express using Context Strong Name
  • eg. namespace DAL class myContext -> DAL.myContext will be the database name
public class MyContext : DbContext
{
  public MyContext() : base("MyOwnDatabaseName") {}
 
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
modelBuilder.Ignore<Privacy>();
modelBuilder.Configurations.Add(new AliasConfiguration());
}
}
  1. Read classes & configurations
  2. Build in-memory Model & mappings
  3. Compare model to EdmMetadata table
  4. Changes? Follow init strategy (default: throw exception)
//on application_start()
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
IDatabaseInitializer
  • CreateDataseIfNotExists
  • DropCreateDatabaseIfModelChanges
  • DropCreateDatabaseAlways
  • YourCustomDBInitialize
 
Code First Migrations
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
  protected override void Seed(TwitterContext context)
  {
  new List<Alias> { ... }.ForEach(b => context.Aliases.Add(b));
base.Seed(context); //calls SaveChanges, so you don't have to
  }
}
Database.SetInitializer(new MyInitializer());
Specify the Database (new or existing)
<connectionStrings>
<add name="TwitterContext" 
connectionString="Data Source=.;Initial Catalog=TweetTweet;Integrated Security=True" 
providerName="System.Data.SqlCient" />
</connectionStrings> 
Make sure that initializer is on default CreateDataseIfNotExists, cause it will think you modified the database since EdmMetadata is missing!
 
  • DbModelBuilder.Conventions.Remove(IncludeMetadataConvention);
  • Database.SetInitialize<MyContext>(null);
  • <appSettings><add key="DatabaseInitializerForType DAL.MyContext, DataAccessAssembly" value="Disabled" /></appSettings>
 
Generic Types in XML configuration
  • IList<T> will be IList`1 and IList[]
  • IDictionary<K,V> will be IDictionary`2 and IDictionary[,]
 
System.Data.Entity.Database
  • Create, CreateIfNotExists, Delete, Exists
  • GetHashCode
  • ExecuteSqlCommand, SqlQuery
  • CompatibleWithModel
  • Initialize, SetInitializer(TContext)
  • Connection, DefaultConnectionFactory
3. More on Entity Framework