static void

Entity Framework v4.1-v6 Code First

EF v4.1 with Code First was released in 2011. EF v6 was released in 2013.
EF v6 was still the recommended EF after EF Core v1 (originally EF7) was released in 2016 (EF Core was missing some critical features, including lazy loading)

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");