English 中文(简体)
为什么我总是得到“不支持类型为基元集合或复杂类型的属性”?
原标题:Why do I keep getting " Properties whose types are collection of primitives or complex types are not supported."?

我有一个实体定义如下(代码由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数据服务公开此类,我会得到以下异常:

The server encountered an error processing the request. The exception message is The property TransactionList on type DomainObjects.EntityFrameworkModel.Gac is not a valid property. Properties whose types are collection of primitives or complex types are not supported. . See server logs for more details. The exception stack trace is:

at System.Data.Services.Providers.ReflectionServiceProvider.BuildTypeProperties(ResourceType parentResourceType, IDictionary2 knownTypes, IDictionary2 childTypes, Queue1 unvisitedTypes, IEnumerable1 entitySets) at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadataForTypes(IDictionary2 knownTypes, IDictionary2 childTypes, Queue1 unvisitedTypes, IEnumerable1 entitySets) at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadata(IDictionary2 knownTypes, IDictionary2 childTypes, IDictionary2 entitySets) at System.Data.Services.Providers.BaseServiceProvider.PopulateMetadata() at System.Data.Services.DataService1.CreateProvider() at System.Data.Services.DataService1.EnsureProviderAndConfigForRequest() at System.Data.Services.DataService1.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)

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

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

Why do I get this exception? I do not see any helpful information in the WCF server log. One useful information for you can be that this entity is representing a database view. I already expose a similar entity which contains the same types of properties int, DateTime, string) and it is working.

** UPDATE ** Data service definiton added (I left out the IDisposable methods):

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
}
最佳回答

Do you expose a property of type IQueryable on your Context class? If not, then that s the problem. In order for a class to be recognized as an entity it must be exposed in an entity set (have a property on the Context class) and it must have a key (either heuristics or DataServiceKey attribute).

还要注意的是,您似乎在基于EF的数据存储上重新定义了基于反射的服务。这将导致更复杂的查询出现问题。WCF DS为反射提供程序和EF提供程序生成的表达式树有些不同(这是必要的,因为它们支持有效表达式的空间)。为反射提供程序生成的树并不总是与EF兼容(反之亦然)。

如果您可以共享更多的Context类,也许有一种方法可以做到这一点,而不必强制使用反射提供程序。我知道您在服务上公开了几个DB,但是您如何运行针对哪个DB运行隔离请求呢?如果它可以通过单独查看请求来确定,并且每个请求只能在单个DB上运行,那么我认为在CreateDataSource中只需要一点逻辑就足够了。

问题回答

我认为WCF试图序列化TransactionList属性。您可以放置告诉WCF跳过属性的属性(类似于[IgnoreDataMember]),或者将该属性转换为方法GetTransationList()。

我不认为你可以向web服务公开泛型。一般来说,我不会向web服务公开ADO.net数据实体。您应该从web服务代码中抽象出数据类。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签