为什么我一直在"不支持其类型是基元或复杂类型集合的属性。"?

时间:2011-11-21 14:52:42

标签: c# entity-framework wcf-data-services odata

我有一个如下定义的实体(由VS2010 POCO生成器生成的代码):

public partial class TransactionList
    {
        public int tlRecordId { get; set; }
        public Nullable<int> tlTracer { get; set; }
        public Nullable<int> tlRecordType { get; set; }
        public Nullable<int> tlPayType { get; set; }
        public Nullable<int> pdmNumber { get; set; }
        public string pdmName { get; set; }
        public string zoneName { get; set; }
        public string groupName { get; set; }
        public Nullable<int> serviceCarNumber { get; set; }
        public Nullable<int> moneyCarNumber { get; set; }
        public Nullable<System.DateTime> tlPayDateTime { get; set; }
        public Nullable<System.DateTime> tlExpDateTime { get; set; }
        public Nullable<int> senderPdmNumber { get; set; }
        public Nullable<int> tlAmount { get; set; }
        public Nullable<int> tlTicketNo { get; set; }
    }

并且该类的第二个部分类(手动编写)包含Key属性。

[DataServiceKey("tlRecordId")]
public partial class TransactionList
{ }

因此,在此类中没有定义复杂的类型/基元集合。如果我使用WCF数据服务公开此类,则会出现以下异常:

  

服务器在处理请求时遇到错误。例外   消息是'属性'TransactionList'类型   'DomainObjects.EntityFrameworkModel.Gac'不是有效的属性。   其类型是基元或复杂类型集合的属性   不受支持。'。请参阅服务器日志以获取更多详例外   堆栈跟踪是:

     

在   System.Data.Services.Providers.ReflectionServiceProvider.BuildTypeProperties(的ResourceType   parentResourceType,IDictionary 2 knownTypes, IDictionary 2   childTypes,队列1 unvisitedTypes, IEnumerable 1 entitySets)at   System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadataForTypes(IDictionary 2 knownTypes, IDictionary 2个childTypes,Queue 1 unvisitedTypes, IEnumerable 1 entitySets)at at   System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadata(IDictionary 2 knownTypes, IDictionary 2个childTypes,IDictionary 2 entitySets) at System.Data.Services.Providers.BaseServiceProvider.PopulateMetadata() at System.Data.Services.DataService 1.CreateProvider()at   System.Data.Services.DataService 1.EnsureProviderAndConfigForRequest() at System.Data.Services.DataService 1.HandleRequest()at   System.Data.Services.DataService`1.ProcessRequestForMessage(流   messageBody)在SyncInvokeProcessRequestForMessage(Object,Object [],   对象[])在   System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(对象   实例,对象[]输入,对象[]&amp;输出)   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)

类Gac包含属性TransactionList,定义如下:

public IQueryable<TransactionList> TransactionList
{
  get { return _myContext.TransactionList.AsNoTracking(); }
}

为什么我会收到此异常?我在WCF服务器日志中看不到任何有用的信息。一个有用的信息可以是该实体表示数据库视图。我已经公开了一个类似的实体,它包含相同类型的属性int,DateTime,string),它正在工作。

**更新**添加了数据服务定义(我省略了IDisposable方法):

public class DummyService : DataService<CustomContext>
{
  protected override CustomContext CreateDataSource()
  {
     //I need a single endpoint exposing data from more databases. Here I pass
     //the data needed for the creation of connection strings
     var dataSource = new CustomContext(new int []{1,2,3});
     return dataSource;
   }
}

///This class represents my single endpoint exposing data from various databases.
///Every database has the same DB schema.
public class CustomContext: IDisposable
{
  private static IList<Gac> _gacList;

  //Here I construct the list of accessible data sources - databases. This list
  // can vary
  public CustomContext(IEnumerable<AreaCodes> areaCodes)
  {
    //This is the list of various databases exposed via OData
    _gacList = new List<Gac>();

    foreach (AreaCodes ac in areaCodes)
    {
      //When calling the constructor of Gac, the DbContext gets created.
      _gacList.Add(new Gac(ac.Id));
    }
  }

  //the entity which will be exposed
  public IQueryable<Gac> Gac
  {
      get { return _gacList != null ? _gacList.AsQueryable() : null; }
  }
}

///This class represents a single data source - a database. 
//All databases are exposed over single endpoint
[DataServiceKey("GacId")]
public class Gac: IDisposable
{
    private MyContext _myContext;
    private int _gacId;

  public Gac(int areaCode)
  {
    //Here I finally create my context
    _myContext= new MyContext("...Connection String Generated based on areaCode");
    _myContext.Configuration.ProxyCreationEnabled = false;
    _myContext.Configuration.LazyLoadingEnabled = false;

    _gacId = areaCode;
  }  

  //This property uniquely identifies a GAC object. It is an entity key.
  public int GacId
  {
    get { return _gacId; }
  }

  //Expose an entity from the EF layer
  public IQueryable<TransactionList> TransactionList
  {
    get { return _myContext.TransactionList.AsNoTracking(); }
  }

  //...Other about 25 IQueryable properties
}

//generated Entity Framework Conceptual Layer
public partial class MyContext: DbContext
{
  //This entity represents my database view which I want to access to
  public DbSet<TransactionList> TransactionList { get; set; }
  //...Other about 25 generic DbSet properties
}

3 个答案:

答案 0 :(得分:2)

您是否在Context类中公开了IQueryable类型的属性? 如果没有,那就是问题所在。为了将类识别为实体,它必须在实体集中公开(在Context类上具有属性)并且必须具有键(启发式或DataServiceKey属性)。

另请注意,您似乎是在基于EF的数据存储上定义基于反射的服务。这将遇到更复杂的查询问题。 WCF DS为反射提供程序与EF提供程序生成稍微不同的表达式树(由于这些表达式支持有效表达式的空间,因此必需)。为反射提供者生成的树并不总是与EF兼容(反之亦然)。

如果您可以共享更多的Context类,可能有一种方法可以在不强制使用反射提供程序的情况下执行此操作。我知道您在服务上公开了几个DB,但是如何运行哪个DB来运行命令请求呢?如果可以通过单独查看请求来确定,并且每个请求只能在单个DB上运行,那么我认为CreateDataSource中的一些逻辑就足够了。

答案 1 :(得分:0)

我认为WCF尝试序列化TransactionList属性。你可以把告诉WCF的属性跳过属性(类似[IgnoreDataMember])或将该属性转换为方法GetTransationList()。

答案 2 :(得分:-1)

我认为您不能将泛型暴露给Web服务。作为一般规则,我不会将ADO.net数据实体暴露给Web服务。您应该从Web服务代码中抽象出数据类。