For an app I'm building, I set up the following architecture:
Front-end:
Silverlight project
nUnit test project
Middle-tier:
WCF Services project
Schemas project
SchemasSL project
DataAccess project
Back-end:
Stored procedures / SQL Server database
Pretty standard stuff, however there's one odd ball in that list, the SchemasSL project. What is this for, you ask?? Try adding more than 1 WCF service reference to your Silverlight project and you'll then enter into what I call "WCF Service Proxy Namespace Hell", or WSPNH for short (it'll catch on, just give it a couple years...) Each service proxy will contain a set of your business objects, each inconveniently located in that service proxy's namespace. Try to cast Service1Proxy.BusinessObjectA to Service2Proxy.BusinessObjectA and then make yourself feel comfortable in WSPNH while the invalid cast build errors pop up.
The solution is to add a reference to your schemas in the Silverlight app and then configure your service references to reuse referenced assemblies by right-clicking on them and doing Configure Service Reference. Easy enough... not! When you try to add the Schemas reference to your Silverlight app, you'll get an error message about how you can't reference a non-Silverlight project in your Silverlight project. F#$%!! This is where SchemasSL comes in. This is simply a Silverlight class library that references all the business objects in the standard Schemas project as links. You can do this by adding existing items, selecting the schema classes, then hitting the down arrow next to the add button and doing "Add as Link".

Now that we've added a reference to our Schemas, we can go ahead and do Update Service References and now all our schemas in our Silverlight app conveniently are located in the Schemas namespace rather than being schismed in the separate service proxy namespaces. At this point you acknowledge that you've just done a little hack but everything is working so you can sleep tonight.
We're done here, this article is over...
Oh wait, I did mention the Entity Framework in the title, didn't I??
I decided that it'd be a good learning experience to try using the Entity Framework/Linq to Entities. Basically you can add new item -> ADO.NET Entity Date Model, point to a database, tell it to add all tables, and it'll auto-generate schemas for you as well as data access methods with a few clicks. It does much more than this, but that's what I planned on using. Below you can see what my entities looked like... It seems simple and fast and usually it is, but I had named all my tables with the convention TABLE_NAME and all my columns with the convention column_name, so all the entity schemas were generated in the same fashion, which looked nasty in C#. I ended up rewriting all the table and column names to conform to C# standards, not something everyone can do, but if you're ditching all your sprocs then it makes it easier.

With all this auto-generated Entity Framework model code, I no longer needed my Schemas project, my DataAccess project, or my stored procedures (you will want to keep some sprocs for complex logic probably but I didn't have any.) By the way, if you run profiler when calling these Entity Framework methods, you'll see that it generates not just dynamic sql, but dirty sql (dynamic sql outside of sprocs.) This made me throw up a little in my mouth but then I read a bunch of articles where it seems that the sproc performance benefits that I had always believed were there may not be vs. dynamic sql. This seems to be due to the fact that dynamic sql can figure out the best execution pattern each run vs the default behavior of sprocs to figure it out only when they're created. If you want to use all sprocs with the Entity Framework you can do so, but for me, it seems the benefits (not having to write hundreds of sprocs and getting to smeer dirty sql in DBA's faces) by far outweigh the minuses (arguable performance gains, security enhancements that may or may not be applicable).
I then reworked my WCF services to work with the Entity Framework, an example service below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using CouponJoe.Services.Models;
using System.Data;
namespace MyNameSpace.Services
{
public class CategoryService : Interfaces.ICategoryService
{
public Category Add(Category category)
{
using (CouponEntities dataContext = new CouponEntities())
{
//set dates.
category.CreateDate = DateTime.Now;
category.ModifiedDate = DateTime.Now;
//save category.
dataContext.AddToCategory(category);
dataContext.SaveChanges();
//return category.
return category;
}
}
public Category Update(Category category)
{
using (CouponEntities dataContext = new CouponEntities())
{
//set date.
category.ModifiedDate = DateTime.Now;
//apply changes.
EntityKey key = dataContext.CreateEntityKey("Category", category);
object originalCategory;
if (dataContext.TryGetObjectByKey(key, out originalCategory))
{
dataContext.ApplyPropertyChanges(key.EntitySetName, category);
}
//save category.
dataContext.SaveChanges();
//return category.
return category;
}
}
public int Delete(Category category)
{
using (CouponEntities dataContext = new CouponEntities())
{
//delete category.
dataContext.Attach(category);
dataContext.DeleteObject(category);
int numRowsAffected = dataContext.SaveChanges();
if (numRowsAffected > 0)
{//return deleted categoryid.
return category.CategoryId;
}
else
{//delete didn't work.
return -1;
}
}
}
public Category Get(int categoryId)
{
using (CouponEntities dataContext = new CouponEntities())
{
//get category by id.
IQueryable<Category> categoryQuery =
from c in dataContext.Category
where c.CategoryId == categoryId
select c;
//return category.
return categoryQuery.FirstOrDefault();
}
}
public Category GetByName(string categoryName)
{
using (CouponEntities dataContext = new CouponEntities())
{
//get category by name.
IQueryable<Category> categoryQuery =
from c in dataContext.Category
where c.CategoryName == categoryName
select c;
//return category.
return categoryQuery.FirstOrDefault();
}
}
public List<Category> Search()
{
using (CouponEntities dataContext = new CouponEntities())
{
//return categorys.
return dataContext.Category.ToList();
}
}
}
}
You can see some fun stuff going on with data access and linq but that's not why we're here. First thing I did was try out the new WCF service methods by running some nunit test cases that I had written and worked with the old code. I removed the reference to the Schemas project in my test project, added a reference to the Services project, then updated the service references (to get the services to use my new Entity Framework business schemas rather than my old custom schemas). This worked and I got every test case passing. At this point I thought I was money....
The next step was to actually use the new WCF service methods in my Silverlight app... and this is where we hit a brick wall... You want to add a reference to your new entity framework schemas to your Silverlight project. You can't add a reference directly to your WCF services project because it's not a Silverlight project. I tried using the same hack as I did before, linking to the Entity Framework Model file (ModelName.edmx) from my SchemasSL project then referencing this in my Silverlight app. Unfortunately, you'll get hundreds of build errors in your SchemasSL project about missing references, including System.Data. Sadly you can't add a reference to it, as it's not a Silverlight reference!! I almost gave up at this point but decided to give something else a try, updating the SchemasSL.csproj file in notepad, and adding the references directly in there to get around the Visual Studio validation.
Here is what I added to the references block of mine:
<Reference Include="mscorlib, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll</HintPath>
</Reference>
<Reference Include="System, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll</HintPath>
</Reference>
<Reference Include="System.Core, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>c:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll</HintPath>
</Reference>
<Reference Include="System.Data, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll</HintPath>
</Reference>
<Reference Include="System.Data.Entity, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>c:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.Entity.dll</HintPath>
</Reference>
<Reference Include="System.Xml, Version=2.0.50727.3053, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll</HintPath>
</Reference>
All of these references were required by the Entity Framework generated model classes, and I had to go through one by one until I finally got the SchemasSL project building. I was burnt out at this point but felt like I had finally gotten where I needed to be, that this was going to work. I referenced the SchemasSL project in my Silverlight project, updated the service references, and voalla, everything worked.. Wait no, that was the happy ending I was hoping for.. Instead, the WCF service proxy classes pooped out (that's the technical term for it), they just didn't generate anything... All of the expected classes for ServiceClients and Async Method calls were just absent from the proxy class. Here's an example proxy class:
namespace MyNameSpace.SL.CarrierServiceProxy {
using System.Runtime.Serialization;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="StructuralObject", Namespace="//schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses">http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses", IsReference=true)]
[System.Runtime.Serialization.KnownTypeAttribute(typeof(CouponJoe.SL.CarrierServiceProxy.EntityObject))]
public partial class StructuralObject {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
public class EntityObject {
}
}
If I went into Configure Service Reference, selected Reuse types in specified referenced assemblies, and checked all except my SchemasSL project, and then it generated the proxy class ok, except as expected it created the schemas under the service proxy namespace.
That made it clear that even though I tricked it into allowing my non-Silverlight references in my Silverlight class library, when generating the proxies it must care about that and that's what caused it to fail. Of course it doesn't give any error messages though in the error or output windows.
So that's where I'm at, still no solution to get this working... Seems like a simple thing to want to use Silverlight, WCF, and the Entity Framework. I mean, 1 company designed all 3, didn't it? Shouldn't they play nice with each other? I went through all this pain and still it isn't working, what gives???
UPDATE:
I removed the reference to my SchemasSL silverlight class library in my Silverlight app, regenerated the service references (so that they'd generate correctly), then manually removed the extra schemas classes from each reference. This isn't something I'd want to do every time I update or add a new service reference but I had come so far that I wanted to follow through and see if I could get this working. After cleaning up the service proxy classes, I ended up getting hundreds of build errors in my Silverlight app about how there are conflicting references. This occurs because my SchemasSL silverlight class library has references to "System" (.NET's System project), whereas my Silverlight app has a reference to "system" (Silverlight's subset System project). This was a clear sign that there was nothing left to do but turn around and go back...
I revived my custom Schemas project and modified my WCF services to expose only those custom schemas rather than the Entity Framework schemas. So for example, when calling an Add method, it would convert the custom schema business object to an Entity Framework schema then save it. When calling a get method, it would use linq to get an Entity Framework schema object, then would conver to a custom schema business object to be returned from the method. Then I could go back to my old hack of linking my customer schema classes to SchemasSL and referencing that within my Silverlight app.
This worked but isn't as nice and clean as I was hoping for, as you end up having two sets of business objects, 1 within your custom schema project and 1 within the generated Entity Framework model code. So it seems at least for now you should expose custom schema objects from your WCF methods and leave Silverlight apps ignorant that the Entity Framework exists, but one can dream for improvements on this in the future...