【问题标题】:Why do I keep getting " Properties whose types are collection of primitives or complex types are not supported."?为什么我不断收到“类型为基元集合或复杂类型的属性不受支持。”?
【发布时间】:2011-11-21 14:52:42
【问题描述】:

我有一个实体定义如下(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 property 'TransactionList' on type “DomainObjects.EntityFrameworkModel.Gac”不是有效属性。 类型是基元或复杂类型的集合的属性 不支持。有关更多详细信息,请参阅服务器日志。例外 堆栈跟踪是:

在 System.Data.Services.Providers.ReflectionServiceProvider.BuildTypeProperties(资源类型 parentResourceType, IDictionary2 knownTypes, IDictionary2 childTypes, Queue1 unvisitedTypes, IEnumerable1 entitySets) 在 System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadataForTypes(IDictionary2 knownTypes, IDictionary2 childTypes,Queue1 unvisitedTypes, IEnumerable1 entitySets)在 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() 在 System.Data.Services.DataService1.EnsureProviderAndConfigForRequest() at System.Data.Services.DataService1.HandleRequest() 在 System.Data.Services.DataService`1.ProcessRequestForMessage(流 messageBody) 在 SyncInvokeProcessRequestForMessage(Object , Object[] , 对象[] ) 在 System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(对象 实例,Object[] 输入,Object[]& 输出)在 System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& RPC)在 System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) 在 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
}

【问题讨论】:

  • 您的数据服务是如何定义的?
  • 'Gac' 是我的数据源中的一个类。此类包含一些属性(我要公开的每个实体一个) - 与上面的 TransactionList 相同。目前我可以毫无问题地公开大约 30 个实体,但如果我添加这个(TransactionList),则会显示异常。
  • 之后,我可以像这样访问我的数据服务:localhost:6000/Gac(1)/TransactionList

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


【解决方案1】:

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

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

如果您可以共享更多 Context 类,也许有一种方法可以在不强制使用反射提供程序的情况下做到这一点。我知道您通过服务公开了几个数据库,但是您如何运行哪个数据库来运行传入请求?如果单看请求就可以确定,并且每个请求只能在单个DB上运行,那么我认为CreateDataSource里面的一点逻辑就足够了。

【讨论】:

  • 感谢您的回答。有一个参数定义应该查询哪个数据库。此参数必须包含在每个请求中。目前,它是一个查询参数 (?gac=0),但我也可以设置一个包含此值的标头...我可以控制客户端和 WCF DS。我将尝试探索 CreateDataSource 方法 - 我想创建到相应的 EF 数据存储或需求的连接 - 意味着探索请求,选择相应的参数(称为“gac”)并创建数据源。我会告诉你它是否有效。
  • 所以我更新了服务定义。上下文类中公开的属性是 IQuerable 类型(请参阅“CustomContext.Gac”)。对应的“Gac”类还定义了一个数据服务键(“GacId”)。
  • 但是你需要上下文类的 IQueryable 属性。对于要正确识别为实体类型的类型,它必须具有键属性,并且必须在上下文中具有 IQueryable 属性。
  • 这是拼图中缺失的一块!我以某种方式误解了您之前的答案。因此,每个应该被识别为实体的属性都必须有一个 IQueryable 属性,即使访问该属性没有任何意义并且会引发异常(如我的情况)。
  • 如果它抛出,那么协议将被破坏。上下文的属性(定义实体集)用于为每个实例生成唯一链接。 OData 当前不支持包含,即只能作为某些父实体的子实体存在的实体。您可以通过导航到其中一个实体并查看其自身链接来查看“损坏”部分。这需要始终是有效的 URL,但如果您的顶级属性抛出,链接将失败。这也意味着 WCF DS 客户端将无法更新这些实体(因为它使用自我/编辑链接来执行此操作)。
【解决方案2】:

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

【讨论】:

  • 其实我需要这个属性,所以不能这么简单跳过。而且我想避免在这里使用服务操作,因为有很多数据库视图,我需要为每个数据库视图进行服务操作。
【解决方案3】:

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

【讨论】:

  • 但这是 WCF 数据服务的目的...我需要将 ADO.NET 数据公开给 Web 服务的功能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 2019-03-17
  • 1970-01-01
  • 1970-01-01
  • 2021-01-26
  • 2023-03-15
  • 2018-01-04
相关资源
最近更新 更多