MSDN Channel 9 has posted a First Look video.
Phones are from Dell, LG, HTC and Samsung.
A .NET and Visual Studio blog.
MSDN Channel 9 has posted a First Look video.
Phones are from Dell, LG, HTC and Samsung.
This is the second post in this series.
The first thing we need to do to enable using our POCOs with EF 4.0 is to decide how we want to handle change tracking and lazy loading of our child collections.
For now, let’s take full advantage of EF’s capabilities and allow it to generate the proxies for lazy loading and full change tracking.
To do this, there are four requirements:
Since List<T> is an implementation of ICollection<T>, we can keep it for our collection, but we need to mark all the properties as virtual. Here are our entities:
using System.Collections.Generic;
namespace Entities.School
{
public class Department
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual List<Course> Courses { get; set; }
}
public class Course
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Department Department { set; get; }
}
}
Note that I have removed the code that kept the Department.Courses collection in sync, when the Course.Department is set. I had hoped that the proxy behavior would replace this “default” behavior, but it looks like from my testing that the proxy synchronization takes place, followed by the “base” behavior. This resulted in two entries being made in the Courses collection each time a Course was assigned to the Department. I removed the base behavior, which means that if the in-memory repository is used, the client code will need to synchronize the collection.
Next, we create the model. Right-click on the model canvas and select Generate Database from Model. This will create the DDL script to create the tables.
Next, blank out the Custom Tool property on the file properties for the EDMX file. This way, no code will be generated for your model. This means we need to write our own ObjectContext class. Many authors recommend creating strongly-type properties for exposing each ObjectSet (Departments, Courses). You can do that, but it isn’t very useful for our Repository interface. Rather, we will create Query<T> and SetOf<T> methods to return the appropriately typed IQueryable and ObjectSet, respectively.
using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
namespace Model
{
public class PocoContext : ObjectContext
{
public PocoContext(string connectString)
: base(connectString)
{
ContextOptions.LazyLoadingEnabled = true;
}
Dictionary<Type, ObjectQuery> roots = new Dictionary<Type, ObjectQuery>();
public ObjectSet<T> SetOf<T>() where T : class
{
ObjectQuery root;
if (!roots.TryGetValue(typeof(T), out root))
{
var set = CreateObjectSet<T>();
roots[typeof(T)] = set;
return set;
}
return (ObjectSet<T>)root;
}
public IQueryable<T> Query<T>() where T : class
{
return (IQueryable<T>)SetOf<T>();
}
}
}
Finally, we create our Repository implementation.
using System.Linq;
namespace Model.School.Model2
{
using Interfaces;
public class SchoolRespository : BaseRepository
{
private PocoContext context;
public SchoolRespository(string connectString = "name=Model2Container")
{
context = new PocoContext(connectString);
}
public override IQueryable<T> Query<T>()
{
return context.Query<T>();
}
public override T New<T>()
{
return context.CreateObject<T>();
}
public override void SetNext<T>(T obj)
{
// no need for this with SQL Server auto-numbering
}
public override void Add<T>(T obj)
{
context.SetOf<T>().AddObject(obj);
}
public override void Remove<T>(T obj)
{
context.SetOf<T>().DeleteObject(obj);
}
public override void Commit()
{
context.SaveChanges();
}
}
}
Here is a test that shows how to use the SchoolRepository that we have created.
[TestMethod]
public void Test_SchoolRepository()
{
IRepository repo = new SchoolRespository();
var count = repo.Query<Department>().Count();
try
{
var math = repo.CreateNext<Department>(d =>
{
d.Name = "Mathematics";
});
var algebra = repo.CreateNext<Course>(c =>
{
c.Name = "Algebra";
c.Department = math;
});
repo.Commit();
repo = new SchoolRespository();
var course = (from c in repo.Query<Course>()
where c.Name == "Algebra"
select c).First();
Assert.IsNotNull(course);
Assert.IsTrue(course.Department.Id == math.Id);
var dept = (from d in repo.Query<Department>()
where d.Name == "Mathematics"
select d).First();
Assert.IsTrue(dept.Courses.Count == 1);
Assert.IsTrue(dept.Courses[0] == course);
}
finally
{
repo = new SchoolRespository();
// remove course and dept
var course = repo.Query<Course>()
.Where(o => o.Name == "Algebra").FirstOrDefault();
if (course != null) repo.Remove<Course>(course);
var dept = repo.Query<Department>()
.Where(o => o.Name == "Mathematics").FirstOrDefault();
if (dept != null) repo.Remove<Department>(dept);
repo.Commit();
}
}
While I know there are a lot of people in the ALT.NET community who like to mock Enitity Framework, that is not what I am talking about.
The objective of this exercise is to develop an Interface that can be used by Business Logic to query and persist data as well as provide and in-memory “mock” for testing or prototyping without a database.
The paradigm used is that of object model aggregates typically found in Domain-driven designs (DDD). This is fortunate because it is the model used by EF, where the aggregates are called ObjectSets.
We want to take advantage of LINQ, because this will allow the consumer of the Repository to add query operators prior to executing the query. The Repository will provide a Query method, a New method, an Add method, a Remove method and a Commit method.
I used the term “a repository-like facade” in the title of this post because traditionally a Repository provides access to a single Aggregate. I have decided to allow an EF Context, which might have several aggregates, to be wrapped by my Repository-implementation. The root aggregate type is determined by the Type parameter affixed to the method. In addition, I will provide a number of convenience methods to chain some of these basic methods is a single method call.
Here is the interface:
using System;
using System.Linq;
namespace Interfaces
{
public interface IRepository
{
// returns a query object for an aggregate root
IQueryable<T> Query<T>();
// returns a new object of the type requested
T New<T>() where T : class;
// returns a new object of the type requested (with the next id set)
T Next<T>() where T : class;
// adds the object to the aggregate root
void Add<T>(T obj) where T : class;
// gets a new object and Adds it to the collection
T AddNew<T>() where T : class;
// gets a new object (with next id set) and Adds it to the collection
T AddNext<T>() where T : class;
// adds a new object with the next id, runs initializer and persists it
T CreateNext<T>(Action<T> initializer) where T : class;
// remove an aggregate root
void Remove<T>(T obj) where T : class;
// persists any changes
void Commit();
}
}
The following code is an abstract implementation of the convenience methods, which are independent of the actual method of creating the new objects and managing them in the context. The methods that are declared abstract are the ones that will need to be implemented by a concrete Repository.
Note: The exception handling in these code listings has been omitted for brevity.
using System;
using System.Linq;
namespace Interfaces
{
abstract public class BaseRepository : IRepository
{
abstract public IQueryable<T> Query<T>();
abstract public T New<T>() where T : class;
abstract public void SetNext<T>(T obj) where T : class;
abstract public void Add<T>(T obj) where T : class;
abstract public void Remove<T>(T obj) where T : class;
abstract public void Commit();
public T Next<T>() where T : class
{
var obj = New<T>();
SetNext<T>(obj);
return obj;
}
public T AddNew<T>() where T : class
{
var obj = New<T>();
Add<T>(obj);
return obj;
}
public T AddNext<T>() where T : class
{
var obj = Next<T>();
Add<T>(obj);
return obj;
}
public T CreateNext<T>(Action<T> initializer) where T : class
{
var obj = AddNext<T>();
if (initializer != null) initializer(obj);
Commit();
return obj;
}
}
}
We can implement an in-memory repository that maintains each type of aggregate root in an ArrayList and uses the Type to find the correct List and operate on it accordingly. To simulate auto-numbered primary keys, we assume that auto-numbered entities will have a long Id property and maintain a single counter for all entities. Of course, you are free to implement this any way that works for you. The Commit() method is a no-op since we don’t plan on persisting the data to disk, but you can implement a Repository that does this if you like.
This implementation works with concrete entity classes (POCOs). I originally had a version that worked with interfaces and the repository mapped the interfaces to an implementation. This worked well with Entity Framework and its generated EntityObject classes, but fell down when I tried to use it with WCF RIA Services.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Interfaces
{
public class InMemRepository : BaseRepository
{
public InMemRepository()
{
// could data load from disk here
}
Dictionary<Type, ArrayList> roots = new Dictionary<Type, ArrayList>();
long counter = DateTime.Now.Ticks;
private ArrayList GetRootList<T>()
{
ArrayList list;
if (!roots.TryGetValue(typeof(T), out list))
{
list = new ArrayList();
roots[typeof(T)] = list;
}
return list;
}
public override IQueryable<T> Query<T>()
{
var list = GetRootList<T>();
return list.Cast<T>().AsQueryable<T>();
}
public override T New<T>()
{
return Activator.CreateInstance<T>();
}
// assumes that there is an Id property (long)
public override void SetNext<T>(T obj)
{
var idProperty = typeof(T).GetProperty("Id");
idProperty.SetValue(obj, counter++, null);
}
public override void Add<T>(T obj)
{
var list = GetRootList<T>();
list.Add(obj);
}
public override void Remove<T>(T obj)
{
var list = GetRootList<T>();
list.Remove(obj);
}
public override void Commit()
{
// code here to write to disk
}
}
}
Here is a unit test that demonstrates how to work with the repository:
[TestClass()]
public class InMemRepositoryTest
{
public class Department
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
private IList<Course> _courses = new List<Course>();
public virtual IList<Course> Courses { get { return _courses; } }
}
public class Course
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
private Department _department;
public virtual Department Department { get { return _department; }
set
{
if (_department != null) _department.Courses.Remove(this);
_department = value;
if (_department != null) _department.Courses.Add(this);
}
}
}
[TestMethod]
public void Test_InMemRepository()
{
IRepository repo = new InMemRepository();
// create some departments
var math = repo.AddNext<Department>();
Assert.IsNotNull(math);
Assert.IsInstanceOfType(math, typeof(Department));
Assert.IsTrue(math.Id > 0);
math.Name = "Mathematics";
repo.Commit();
// use the convenience method
var compsci = repo.CreateNext<Department>(d =>
{
d.Name = "Computer Science";
});
Assert.IsNotNull(compsci);
Assert.IsInstanceOfType(compsci, typeof(Department));
Assert.IsTrue(compsci.Id > 0);
Assert.IsTrue(compsci.Name == "Computer Science");
var count = repo.Query<Department>().Count();
Assert.AreEqual<int>(count, 2);
// create some courses
var algebra = repo.CreateNext<Course>(c =>
{
c.Name = "Algebra";
c.Department = math;
});
var trig = repo.CreateNext<Course>(c =>
{
c.Name = "Trigonometry";
c.Department = math;
});
var lisp = repo.CreateNext<Course>(c =>
{
c.Name = "Lisp";
c.Department = math;
});
Assert.AreEqual<int>(3, repo.Query<Course>().Count());
Assert.AreEqual<int>(3, math.Courses.Count());
Assert.AreEqual<int>(0, compsci.Courses.Count());
lisp.Department = compsci;
Assert.AreEqual<int>(2, math.Courses.Count());
Assert.AreEqual<int>(1, compsci.Courses.Count());
}
}
My next post will show how to write a Repository implementation for Entity Framework.
Due to rumors swiling about the demise of Silverlight at the hands of HTML 5, Microsoft felt compelled to publish the following on the Silverlight Blog:
In about half the time HTML 5 has been under design, we've created Silverlight and shipped four major versions of it. And it's still unclear exactly when HTML 5 and its related specs will be complete with full test suites. For HTML 5 to be really targetable, the spec has to stabilize, browsers have to all implement the specs in the same way, and over a billion people have to install a new browser or buy a new device or machine. That's going to take a while. And by the time HTML 5 is broadly targetable, Silverlight will have evolved significantly. Meanwhile, Silverlight is here now and works in all popular browsers and OS's.
…Silverlight is much more than a browser technology.
There are three areas of investment for Silverlight outside the browser: the desktop, the mobile device, and the living room. Powerful desktop applications can be created with Silverlight today. These applications don't require a separate download—any desktop user with Silverlight installed has these capabilities. These apps can be discovered and downloaded in the browser but are standalone applications that are painless to install and delete. Silverlight now also runs on mobile devices and is the main development platform for the new Windows Phone 7 devices. Developers that learned Silverlight instantly became mobile developers. Lastly, at NAB and the Silverlight 4 launch this year we showed how Silverlight can be used as a powerful, rich platform for living room devices as well.
Read the whole thing. It’s long but worth the time.
Microsoft has released a refresh for Silverlight 4 to fix some bugs. Read Tim Heuer’s blog post.
If you are developing in LightSwitch, then you will need the new Developer Runtime and SDK.
The Silverlight Tools package has also been updated with the new SDK and runtime.
According to a tweet from Scott Guthrie, Windows Phone 7 is released to manufacturing today. The final tools will be ready for download in two weeks, on September 16.
VS 2010 Express for Windows Phone 7 and Expression Blend for Phone 7 will be free.
Take a look at the Windows 7 Jump Start on-line training while you’re waiting.
Labs and code can be found in the Training Kit.
Tim Anderson has two informative posts about Microsoft’s LightSwitch. I’ll try to summarize them here.
Ten things you need to know about LightSwitch (Tim Anderson):
Visual Studio LightSwitch – model-driven architecture for the mainstream (Tim Anderson):
Tim spoke to two LightSwitch team members. They couldn’t speculate on a release date, but did say that Windows Phone 7 will not be targeted in the first release. Perhaps it will be added later. The product was designed to allow different output formats for applications, but Mac is not considered high-priority. The development of LightSwitch had an influence on the design of some WCF RIA Services features.
While Microsoft seems to be positioning LightSwitch as a tool for the masses to develop departmental applications, it remains to be seen if it will catch on. Perhaps on a larger scale, Microsoft intends to deliver on the promise of model-driven application generation. And that would be no small feat.
Microsoft has released the first beta of its LightSwitch product.
LightSwitch allows you to create web-based data-driven applications, using industry-standard patterns and technologies: Entity Framework, WCF RIA Services and Silverlight.
More LightSwitch links: