What am I doing wrong? wcf & entity-framework
I just came across WCF
today and started learning it. However, once I tried to combine it with the EntityFramework
it stopped working. I created a entity model for my database dtcinvoicerdb
, turned off code generation and wrote the Entity/ObjectContext
classes myself. The service is supposed to fetch all the Employees
from the database.
Everything works fine, the project compiles and the WcfTestClient opens up, but when I try to Invoke the GetEmployees()
operation I get the following exception:
Mapping and metadata information could not be found for EntityType 'DtcInvoicerDbModel.Employee'.
I know there's a lot of code below, but it's all pretty basic so bear with me.
entity image and model properties http://img716.imageshack.us/img716/1397/wcf.png
/Entities/DtcInvoicerDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using DtcInvoicerDbModel;
namespace DtcInvoicerServiceLibrary
{
public class DtcInvoicerDbContext:ObjectContext
{
public DtcInvoicerDbContext():base("name=DtcInvoicerDbEntities", "DtcInvoicerDbEntities")
{
}
#region public ObjectSet<Employee> Employees;
private ObjectSet<Employee> _Employees;
public ObjectSet<Employee> Employees
{
get
{
return (_Employees == null) ? (_Employees = base.CreateObjectSet<Employee>("Employees")) : _Employees;
}
}
#endregion
}
}
/Entities/Employee.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Runtime.Serialization;
namespace DtcInvoicerDbModel
{
[DataContract]
public class Employee
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public string Username { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public DateTime EmployeeSince { get; set; }
}
}
/IDtcInvoicerServicer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using DtcInvoicerDbModel;
namespace DtcInvoicerServiceLibrary
{
[ServiceContract]
public interface IDtcInvoicerService
{
[OperationContract]
List<Employee> GetEmployees();
}
}
/DtcInvoicerService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using DtcInvoicerDbModel;
namespace 开发者_Go百科DtcInvoicerServiceLibrary
{
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, IncludeExceptionDetailInFaults=true)]
public class DtcInvoicerService:IDtcInvoicerService
{
private DtcInvoicerDbContext db = new DtcInvoicerDbContext();
public List<Employee> GetEmployees()
{
return db.Employees.Where(x => x.ID > 0).ToList();
}
}
}
I know this doesn't answer your question, but with your service, have you considered using WCF Data Services instead? Your service is returning your entities to your client -- WCF Data Services can provide that for you and also give your client the ability to use LINQ queries to filter and/or project your results.
You could add a WCF Data Service item (InvoicerService.svc) to your project and set up the service class like so:
public class InvoicerService : DataService<DtcInvoicerDbEntities>
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("Employees", EntitySetRights.AllRead);
config.SetEntitySetPageSize("*", 25);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
You could then access your employees via a GET request using the URL:
http://server:port/InvoicerService.svc/Employees?$filter=ID gt 0
Again, not the answer to your question, but perhaps an alternative. Just thought I'd add it.
Hope this helps!
Ahh got it to work after some more searching on stackoverflow and comparing with the generated code.
Errors: I was missing a property IsActive
, and I didn't add Edm attributes to the class and it's properties.
For anyone that comes across the same problem, remember to set the EdmScalarProperty (or other property type) attribute on all your properties, and don't forget to set which property acts as the EntityKey
(e.g. ID).
Here's what my Employee
class looks like now, and it works.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.Runtime.Serialization;
[assembly: EdmSchemaAttribute()]
namespace DtcInvoicerDbModel
{
[EdmEntityType(NamespaceName="DtcInvoicerDbModel", Name="Employee")]
[DataContract(IsReference=true)]
public class Employee
{
[DataMember]
[EdmScalarProperty(EntityKeyProperty = true, IsNullable = false)]
public int ID { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
public bool IsActive { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
public string FirstName { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
public string LastName { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
public string Username { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = false)]
public string Password { get; set; }
[DataMember]
[EdmScalarProperty(EntityKeyProperty = false, IsNullable = true)]
public DateTime? EmployeeSince { get; set; }
}
}
精彩评论