locked
WCF OData Service and EF 6 issue RRS feed

  • Question

  • Hi,

    I am using WCF Data Service (Odata) with .NET framework 4.5.1 and EF 6.1. I have used code first approach to create EF model. When I reference this EF model (AddProjectModel.cs) to WCF OData Service (WcfDataService1.svc), it throws following error: 

    Error:

    The server encountered an error processing the request. The exception message is 'On data context type 'AddProjectModel', there is a top IQueryable property 'Assets' whose element type is not an entity type. Make sure that the IQueryable property is of entity type or specify the IgnoreProperties attribute on the data context type to ignore this property.'. See server logs for more details. The exception stack trace is:

    at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadata(ProviderMetadataCacheItem metadataCacheItem) at System.Data.Services.Providers.BaseServiceProvider.LoadMetadata(Boolean skipServiceOperations) at System.Data.Services.DataService`1.CreateInternalProvider(Object dataSourceInstance) at System.Data.Services.DataService`1.CreateMetadataAndQueryProviders(IDataServiceMetadataProvider& metadataProviderInstance, IDataServiceQueryProvider& queryProviderInstance, Object& dataSourceInstance, Boolean& isInternallyCreatedProvider) at System.Data.Services.DataService`1.CreateProvider() at System.Data.Services.DataService`1.HandleRequest() at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody) at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] ) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

    Here is my WCF Data Service:     WcfDataService1.svc

    namespace AddProjectService
    {
      public class WcfDataService1 : DataService<AddProjectModel>
        {
            // This method is called only once to initialize service-wide policies.
            public static void InitializeService(DataServiceConfiguration config)
            {
                // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
                // Examples:
                config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
                config.SetServiceOperationAccessRule("*", ServiceOperationRights.All);
                config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
            }
        }
    }

    My Code First Model:     AddProjectModel.cs

     public partial class AddProjectModel : DbContext
      {
        public AddProjectModel()
          : base("name=AddProjectModel")
        {
        }
    
        public virtual DbSet<Asset> Assets { get; set; }
        public virtual DbSet<Project> Projects { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          modelBuilder.Configurations.Add(new AssetMap());
          modelBuilder.Configurations.Add(new ProjectMap());   
        }         
      }  
    
      public class AssetMap : EntityTypeConfiguration<Asset>
      {
        public AssetMap()
        {
          this.Property(a => a.AssetId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);      
          this.HasMany(a => a.Projects).WithRequired(p => p.Asset).HasForeignKey(p => p.AssetId);
    
          //table  & column mappings
          this.ToTable("TBLASSET");
          this.Property(a => a.AssetId).HasColumnName("ASSETID");
          this.Property(a => a.AssetLevelId).HasColumnName("ASSETLEVELID");
          this.Property(a => a.AssetNumber).HasColumnName("ASSETNUMBER");
          this.Property(a => a.Name).HasColumnName("NAME");
          this.Property(a => a.AssetTypeId).HasColumnName("ASSETTYPEID");      
        }
      }  
    
      public class ProjectMap : EntityTypeConfiguration<Project>
      {
        public ProjectMap()
        {
          this.Property(p => p.ProjectId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
          this.HasMany(p => p.SchedulePhases).WithRequired(sp => sp.Project).HasForeignKey(sp => sp.ProjectId); 
    
          //table & column mappings
          this.ToTable("TBLPROJECT");
          this.Property(p => p.ProjectId).HasColumnName("PROJECTID");
          this.Property(p => p.AssetId).HasColumnName("ASSETID");
          this.Property(p => p.CapitalCategoryId).HasColumnName("CAPITALCATEGORYID");
          this.Property(p => p.Comments).HasColumnName("COMMENTS");
          this.Property(p => p.DesignationId).HasColumnName("DESIGNATIONID");
          this.Property(p => p.DispositionId).HasColumnName("DISPOSITIONID");
          this.Property(p => p.FMSNumber).HasColumnName("FMSNUMBER");
          this.Property(p => p.FundingSourceId).HasColumnName("FUNDINGSOURCEID");
          this.Property(p => p.ImplementerId).HasColumnName("IMPLEMENTERID");
          this.Property(p => p.IsApproved).HasColumnName("ISAPPROVED");
          this.Property(p => p.IsDeferred).HasColumnName("ISDEFERRED");
          this.Property(p => p.IsLongTermLease).HasColumnName("ISLONGTERMLEASE");
          this.Property(p => p.IsRollover).HasColumnName("ISROLLOVER");
          this.Property(p => p.IsSidewalkBridge).HasColumnName("ISSIDEWALKBRIDGE");
          this.Property(p => p.JobDescription).HasColumnName("JOBDESCRIPTION");
          this.Property(p => p.JobType).HasColumnName("JOBTYPE");
          this.Property(p => p.OrganizationId).HasColumnName("ORGANIZATIONID");
          this.Property(p => p.ProgramCategoryId).HasColumnName("PROGRAMCATEGORYID");
          this.Property(p => p.DsfId).HasColumnName("DSFID");
          this.Property(p => p.StatusId).HasColumnName("STATUSID");
    
          this.Map<DomainObjectModel.ObjectModel.Project.ProjectCIP>(m => m.Requires("PROJECTTYPEID").HasValue(15))
              .Map<DomainObjectModel.ObjectModel.Project.ProjectCapacity>(m => m.Requires("PROJECTTYPEID").HasValue(2));
        }
      }
     

    Asset class:

     public class Asset
      {
        public Asset()
        {
          Projects = new HashSet<Project>();      
        }
    
        [Key]
        public decimal AssetId { get; set; }
    
        [StringLength(20)]
        public string AssetNumber { get; set; }
    
        [StringLength(100)]
        public string Name { get; set; }
        
        public decimal? AssetLevelId { get; set; }
    
        public decimal? AssetTypeId { get; set; }
    
        public virtual ICollection<Project> Projects { get; set; }    
      }

    Project class:

     public class Project
      {
        public Project()
        {      
        } 
    
        [Key]
        public decimal ProjectId { get; set; }
    
        public decimal AssetId { get; set; }
    
        public decimal CapitalCategoryId { get; set; }
    
        //public decimal ProjectTypeId { get; set; }
    
        public decimal ProgramCategoryId { get; set; }   
    
        [StringLength(1024)]
        public string Comments { get; set; }
    
        public decimal ImplementerId { get; set; }
    
        public decimal StatusId { get; set; }
    
        public decimal DsfId { get; set; }
    
        [StringLength(20)]
        public string FMSNumber { get; set; }
    
        [StringLength(1024)]
        public string JobDescription { get; set; }
    
        [StringLength(2)]
        public string JobType { get; set; }
    
        public decimal OrganizationId { get; set; }
    
        [Required][StringLength(1)]
        public string IsRollover { get; set; }
    
        [Required][StringLength(1)]
        public string IsDeferred { get; set; }
    
        [Required][StringLength(1)]
        public string IsApproved { get; set; }
    
        [StringLength(1)]
        public string IsSidewalkBridge { get; set; }
    
        public decimal FundingSourceId { get; set; }
    
        public decimal? DesignationId { get; set; }
    
        public decimal? DispositionId { get; set; }
    
        [Required][StringLength(1)]
        public string IsLongTermLease { get; set; }
        
        public virtual Asset Asset { get; set; }   
      }

    I don't know how to resolve this issue. Could you please tell me what I am missing here?

    Thanks,

    Tuesday, September 16, 2014 3:42 PM

Answers

  • Thanks Shawn. I have figured that out and provided [DataServiceKey] attribute on each POCO classes to set the primary key. It resolved the issue. Now I can expose the entities using oData service. Please see below..

    URL:  http://localhost:60290/WcfDataService1.svc/

    <?xml version="1.0" encoding="utf-8" ?> 
    -<service xml:base="http://localhost:60290/WcfDataService1.svc/" xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
    -  <workspace>
      	<atom:title>Default</atom:title> 
    - 	<collection href="Assets">
      	   <atom:title>Assets</atom:title> 
            </collection>
    - 	<collection href="Projects">
      	   <atom:title>Projects</atom:title> 
            </collection>- 
       </workspace>
    </service>

    But when I try to access the entity collection, it throws an error. Please see below for error stack..

     URL:   http://localhost:60290/WcfDataService1.svc/Assets

     ERROR 1: 

      <?xml version="1.0" encoding="utf-8" ?> 
    - <m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
        <m:code /> 
        <m:message xml:lang="en-US">An error occurred while processing this request.</m:message> 
    -   <m:innererror>
          <m:message>Operation could destabilize the runtime.</m:message> 
          <m:type>System.Security.VerificationException</m:type> 
          <m:stacktrace>at queryable_reader(Object ) at System.Data.Services.Providers.ReflectionServiceProvider.GetQueryRootForResourceSet(ResourceSet container) at System.Data.Services.Providers.ReflectionDataServiceProvider.GetQueryRootForResourceSet(ResourceSet resourceSet) at System.Data.Services.Providers.DataServiceProviderWrapper.GetQueryRootForResourceSet(ResourceSetWrapper resourceSet) at System.Data.Services.RequestUriProcessor.ComposeExpressionForEntitySet(SegmentInfo segment, IDataService service, Boolean isLastSegment, Boolean checkRights) at System.Data.Services.RequestUriProcessor.ComposeExpressionForSegments(IList`1 segments, IDataService service, Boolean isCrossReferencingUri) at System.Data.Services.RequestUriProcessor.ProcessRequestUri(Uri absoluteRequestUri, IDataService service, Boolean internalQuery) at System.Data.Services.DataService`1.ProcessIncomingRequestUri() at System.Data.Services.DataService`1.HandleRequest()</m:stacktrace> 
        </m:innererror>
      </m:error>

    --------------------------------------------------- ******************-------------------------------------------------------

    In following scenario, if I don't use virtual keyword with the properties in my POCO model class (AddProjectModel.cs) , I am getting different error (ERROR 2). I have removed virtual key word for following propertities:

    DbSet<Asset> Assets { get; set;} and

    DbSet<Project> Projects {get; set;}

    POCO Model:  AddProjectModel.cs

    public partial class AddProjectModel : DbContext
      {
        public AddProjectModel()
          : base("name=AddProjectModel")
        {
        }
    
        public DbSet<Asset> Assets { get; set; }
        public DbSet<Project> Projects { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          modelBuilder.Configurations.Add(new AssetMap());
          modelBuilder.Configurations.Add(new ProjectMap());   
        }         
      }    

    ERROR 2: 

    <?xml version="1.0" encoding="utf-8"?> 
    <feed xml:base="http://localhost:60290/WcfDataService1.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><id>http://localhost:60290/WcfDataService1.svc/Assets</id><title type="text">Assets</title>
    <updated>2014-09-17T19:00:59Z</updated>
    <link rel="self" title="Assets" href="Assets" />
    <m:error>
      <m:code />
      <m:message xml:lang="en-US">Internal Server Error. The type 'System.Data.Entity.DynamicProxies.Asset_42B2D9DF367B0053FCF4640271A0B802C1B6B9A1B342C427FD3E438A8720893D' is not a complex type or an entity type.
      </m:message>
    </m:error>

    Question 1: How do I resolve ERROR 1?

    Question 2: - I am trying to understand why it gives me ERROR 2 when I don't use virtual key word?

    Question 3: How to resolve ERROR 2?

    I appreciate all your helps,

    Thanks,




    • Edited by Russo1991 Wednesday, September 17, 2014 7:07 PM
    • Marked as answer by Shawn Zhao Tuesday, September 23, 2014 9:31 AM
    Wednesday, September 17, 2014 1:48 PM
    • Marked as answer by Shawn Zhao Tuesday, September 23, 2014 9:30 AM
    Thursday, September 18, 2014 8:16 AM

All replies

  • You have a EF issue and not a WCF issue. You should post to the MSDN EF forum.
    Wednesday, September 17, 2014 12:12 AM
  • Hi,

    For this issue, according to the error message, this can mean two things. Either you have a property that cannot be processed by the Entity Data Model used by OData or OData could not find a primary key for your class.

    OData requires a primary key for every resource. If you use the reflection based provider, it uses one of the following mechanisms to find the primary key:

    • via the [DataServiceKey] attribute
    • by looking for a "FooID" property, where the type is called "Foo"
    • by looking for an "ID" property

    For detailed information:

    http://bartwullems.blogspot.com/2010/06/odata-using-reflection-based-provider.html

    https://blogs.blackmarble.co.uk/blogs/jfowler/post/2012/05/18/Error-after-upgrading-to-Wcf-Data-Service-50.aspx

    http://blog.marcgravell.com/2008/12/astoria-and-linq-to-sql-getting-started.html

    Regards

    Wednesday, September 17, 2014 6:16 AM
  • Thanks Shawn. I have figured that out and provided [DataServiceKey] attribute on each POCO classes to set the primary key. It resolved the issue. Now I can expose the entities using oData service. Please see below..

    URL:  http://localhost:60290/WcfDataService1.svc/

    <?xml version="1.0" encoding="utf-8" ?> 
    -<service xml:base="http://localhost:60290/WcfDataService1.svc/" xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
    -  <workspace>
      	<atom:title>Default</atom:title> 
    - 	<collection href="Assets">
      	   <atom:title>Assets</atom:title> 
            </collection>
    - 	<collection href="Projects">
      	   <atom:title>Projects</atom:title> 
            </collection>- 
       </workspace>
    </service>

    But when I try to access the entity collection, it throws an error. Please see below for error stack..

     URL:   http://localhost:60290/WcfDataService1.svc/Assets

     ERROR 1: 

      <?xml version="1.0" encoding="utf-8" ?> 
    - <m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
        <m:code /> 
        <m:message xml:lang="en-US">An error occurred while processing this request.</m:message> 
    -   <m:innererror>
          <m:message>Operation could destabilize the runtime.</m:message> 
          <m:type>System.Security.VerificationException</m:type> 
          <m:stacktrace>at queryable_reader(Object ) at System.Data.Services.Providers.ReflectionServiceProvider.GetQueryRootForResourceSet(ResourceSet container) at System.Data.Services.Providers.ReflectionDataServiceProvider.GetQueryRootForResourceSet(ResourceSet resourceSet) at System.Data.Services.Providers.DataServiceProviderWrapper.GetQueryRootForResourceSet(ResourceSetWrapper resourceSet) at System.Data.Services.RequestUriProcessor.ComposeExpressionForEntitySet(SegmentInfo segment, IDataService service, Boolean isLastSegment, Boolean checkRights) at System.Data.Services.RequestUriProcessor.ComposeExpressionForSegments(IList`1 segments, IDataService service, Boolean isCrossReferencingUri) at System.Data.Services.RequestUriProcessor.ProcessRequestUri(Uri absoluteRequestUri, IDataService service, Boolean internalQuery) at System.Data.Services.DataService`1.ProcessIncomingRequestUri() at System.Data.Services.DataService`1.HandleRequest()</m:stacktrace> 
        </m:innererror>
      </m:error>

    --------------------------------------------------- ******************-------------------------------------------------------

    In following scenario, if I don't use virtual keyword with the properties in my POCO model class (AddProjectModel.cs) , I am getting different error (ERROR 2). I have removed virtual key word for following propertities:

    DbSet<Asset> Assets { get; set;} and

    DbSet<Project> Projects {get; set;}

    POCO Model:  AddProjectModel.cs

    public partial class AddProjectModel : DbContext
      {
        public AddProjectModel()
          : base("name=AddProjectModel")
        {
        }
    
        public DbSet<Asset> Assets { get; set; }
        public DbSet<Project> Projects { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
          modelBuilder.Configurations.Add(new AssetMap());
          modelBuilder.Configurations.Add(new ProjectMap());   
        }         
      }    

    ERROR 2: 

    <?xml version="1.0" encoding="utf-8"?> 
    <feed xml:base="http://localhost:60290/WcfDataService1.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><id>http://localhost:60290/WcfDataService1.svc/Assets</id><title type="text">Assets</title>
    <updated>2014-09-17T19:00:59Z</updated>
    <link rel="self" title="Assets" href="Assets" />
    <m:error>
      <m:code />
      <m:message xml:lang="en-US">Internal Server Error. The type 'System.Data.Entity.DynamicProxies.Asset_42B2D9DF367B0053FCF4640271A0B802C1B6B9A1B342C427FD3E438A8720893D' is not a complex type or an entity type.
      </m:message>
    </m:error>

    Question 1: How do I resolve ERROR 1?

    Question 2: - I am trying to understand why it gives me ERROR 2 when I don't use virtual key word?

    Question 3: How to resolve ERROR 2?

    I appreciate all your helps,

    Thanks,




    • Edited by Russo1991 Wednesday, September 17, 2014 7:07 PM
    • Marked as answer by Shawn Zhao Tuesday, September 23, 2014 9:31 AM
    Wednesday, September 17, 2014 1:48 PM
    • Marked as answer by Shawn Zhao Tuesday, September 23, 2014 9:30 AM
    Thursday, September 18, 2014 8:16 AM