static void

Entity Framework Code First

Links

You can't have a code first model in the same project as an EDMX model.

DbContext (Unit of Work)

DbContext = EF 4 ObjectContext

It's better to expose DbSets as IDbSet. DbSet properties can be readonly: get { return Set<T>(); }

public IDbSet<Product> Products
{
    get { return Set<Product>(); }
}

DbSet

DbSet<T> = EF 4 ObjectSet

Query set.Find(1) //Get by id (from 1st level cache, then store, or null)
Insert set.Add(entity)
Update

Either load and change...

var entity = context.Products.Find(1);
entity.Code = "232A";
context.SaveChanges();

(DO NOT set.Add ... you'll create a new entity) ... OR...

//create a detached entity and populate *all* fields
var entity = new Product();
entity.Id = 1; //set explicitly
entity.Code = "233A";
//set the state manually
DbEntityEntry<Product> entry = context.Entry(entity);
entry.State = EntityState.Modified;
context.SaveChanges();

Attach

var entity = new Product();
entity.Code = "123";
var fk = new Category { Id = 1 };
context.Products.Attach(fk); //State == EntityState.Unchanged
//add a fk relation without loading the actual opbject
entity.Category = fk;
context.Products.Add(entity);

InsertOrUpdate

You need to know the primary key.

public void InsertOrUpdate(DbContext context, Station entity)
{
    context.Entry(entity).State = entity.Id == 0 ?
                                   EntityState.Added :
                                   EntityState.Modified;
}

Exceptions

try
{
    context.SaveChanges();
}
catch (System.Data.Entity.Validation.DbEntityValidationException validationException)
{
    foreach (var error in validationException.EntityValidationErrors)
    {
        var entry = error.Entry;
        foreach (var err in error.ValidationErrors)
        {
            Debug.WriteLine(err.PropertyName + " " + err.ErrorMessage);
        }
    }
}
catch (DbUpdateConcurrencyException concurrencyException)
{
    //assume just one
    var dbEntityEntry = concurrencyException.Entries.First();
    //store wins
    dbEntityEntry.Reload();
    //OR client wins
    var dbPropertyValues = dbEntityEntry.GetDatabaseValues();
    dbEntityEntry.OriginalValues.SetValues(dbPropertyValues); //orig = db
}
catch (DbUpdateException updateException)
{
    //often in innerException
    if (updateException.InnerException != null)
        Debug.WriteLine(updateException.InnerException.Message);
    //which exceptions does it relate to
    foreach (var entry in updateException.Entries)
    {
        Debug.WriteLine(entry.Entity);
    }
}

Lazy/Eager loading

//load all into memory
context.Categories.Load();
//get all without tracking (NOT in dbContext)
var cachableCategories = context.Categories.AsNoTracking().ToList();

WCF/WebAPI may have problems with proxies so:

context.Configuration.ProxyCreationEnabled = false;
context.Configuration.LazyLoadingEnabled = false;

You may have to have [System.Runtime.Serialization.IgnoreDataMember] on association properties to foil the DataContractSerializer.

Other DbSet properties

//what's changed...
foreach (var dbEntityEntry in context.ChangeTracker.Entries<Category>())
{
    Debug.WriteLine(dbEntityEntry.State);
}

Entities

To get a proxy, you can't new it up, use DbSet.Create() - eg context.Products.Create().
Also you can create derived classes: context.Products.Create<FoodProduct>()

//create a proxy (NOT ADDED TO SET)
var entity = context.Categories.Create();

Change tracking

For POCOs/lazy loading proxies, DetectChanges is used (implicitly or explicitly); change tracking proxies have it built in.

DbEntityEntry<Category> entry = context.Entry(entity);
//entry.State
var prop = entry.Property(x => x.Name);
//prop.IsModified;
//prop.OriginalValue vs prop.CurrentValue
entry.GetDatabaseValues(); //force a db update
 
//automap
var clone = new Category();
context.Entry(entity).CurrentValues.SetValues(clone);

Raw SQL

//can grab DbSet entities (by default tracked)
//or any type incl. primitive types
context.Categories.SqlQuery("select * from categories"); //only DbSet, not IDbSet
var categoriesByRawSql = context.Database.SqlQuery<Category>(
    "exec mysproc @p1, @p2",
    new SqlParameter("p1", 1),
    new SqlParameter("p2", 2));
context.Database.ExecuteSqlCommand("drop database");