具有子集合的实体在 WCF 中导致问题:如果您使用 DataContractSerializer,请考虑使用 DataContractResolver

Posted

技术标签:

【中文标题】具有子集合的实体在 WCF 中导致问题:如果您使用 DataContractSerializer,请考虑使用 DataContractResolver【英文标题】:Entity having child collections causing issues in WCF : Consider using a DataContractResolver if you are using DataContractSerializer 【发布时间】:2019-06-12 09:01:25 【问题描述】:

已经努力解决这个问题一天了。 EF也是新手!!

我需要将我的产品列表及其子系列放在一起。

我的 Model.tt 在 DataModel.dll 中,我在 WCF 服务和我的客户端中都引用了它。当实体有子集合时,我收到此错误。猜猜这是由于实体的公共虚拟ICollection。我该如何解决这个问题?

尝试将 [KnownType(typeof(entity.Name))] 放入我的 Model.tt 会有帮助吗?如果是这样,如何让 entity.Name 在我的 Model.tt 中通用传递?

试过了:

    将 [Serializable] 属性放入我的 Model.tt LazyLoadingEnabled="false"

跟踪日志中捕获的错误:

类型 'System.Data.Entity.DynamicProxies.Entity_Product_F540EDA252AD69FEA102E0C9AB0167D5397996ADA4679FA9C4089B58B9766924' 与数据合同名:预计不会 'Entity_Product_F540EDA252AD69FEA102E0C9AB0167D5397996ADA4679FA9C4089B58B9766924 http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'。如果您使用 DataContractSerializer 或将任何静态未知的类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中。

尝试序列化参数http://tempuri.org/:GetAllProductResult 时出错。该消息的InnerException是‘用数据合同名称‘Entity_Product_F540EDA252AD69FEA102E0C9AB0167D5397996ADA4679FA9C4089B58B9766924“类型’System.Data.Entity.DynamicProxies.Entity_Product_F540EDA252AD69FEA102E0C9AB0167D5397996ADA4679FA9C4089B58B9766924:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies’预计不会。如果您正在使用 DataContractSerializer 或将任何静态未知的类型添加到已知类型列表中,请考虑使用 DataContractResolver - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给序列化程序的已知类型列表中。有关详细信息,请参阅 InnerException。

自动生成的实体:

   [Serializable] 
public partial class Entity_Product

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Entity_Product()
    
        this.tbl_ManufacturerDetail = new HashSet<Entity_ManufacturerDetail>();
        this.tbl_ProductDetails = new HashSet<Entity_ProductDetails>();
    

    public int ProductId  get; set;  
    public string Administration  get; set; 
    public string Manufacturer  get; set; 
    public Nullable<decimal> Price  get; set;  
    public Nullable<bool> IsEnabled  get; set; 
    public Nullable<System.DateTime> CreatedOn  get; set; 
    public string CreatedBy  get; set; 
    public Nullable<System.DateTime> UpdatedOn  get; set; 
    public string UpdatedBy  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Entity_ManufacturerDetail> tbl_ManufacturerDetail  get; set; 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Entity_ProductDetails> tbl_ProductDetails  get; set; 

【问题讨论】:

你试过[KnownType(typeof(Entity_ManufacturerDetail))][KnownType(typeof(Entity_ProductDetails))]吗? @JohnEphraimTugado 这是 DB first EF,所以实体是从 DB 生成的。唯一的方法是添加 Model.tt 不知道如何动态获取实体名称。 发现,产品正在引用 ProductDetails,而 ProductDetails 的产品 id 再次引用回 Products 等等……Entity_ManufacturerDetail 的情况相同。所以它是无限循环。也许是因为那个?如果是这样,我怎样才能停止这种无休止的引用? 如果这是您的问题,您可以将 [DataContract(IsReference = true)] 添加到具有无限参考的类中。请参考https://***.com/questions/18392402/circular-references-preventing-serialization-of-object-graph 【参考方案1】:

我不确定这是否是您问题的解决方案,但这可以让您在Model.tt 中添加[KnownType(typeof(entity.Name))]。不完全是实体名称,而是每个集合导航属性的实体名称。

这是我修改后的Model.tt 文件的第 1-70 行。我只更改了 cmets //START MODIFICATION//END MODIFICATION 之间的行。

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF6.Utility.CS.ttinclude"#><#@ 
 output extension=".cs"#><#

const string inputFile = @"Model.edmx";
var textTransform = DynamicTextTransformation.Create(this);
var code = new CodeGenerationTools(this);
var ef = new MetadataTools(this);
var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
var fileManager = EntityFrameworkTemplateFileManager.Create(this);
var itemCollection = new EdmMetadataLoader(textTransform.Host, textTransform.Errors).CreateEdmItemCollection(inputFile);
var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);

if (!typeMapper.VerifyCaseInsensitiveTypeUniqueness(typeMapper.GetAllGlobalItems(itemCollection), inputFile))

    return string.Empty;


WriteHeader(codeStringGenerator, fileManager);

foreach (var entity in typeMapper.GetItemsToGenerate<EntityType>(itemCollection))

    fileManager.StartNewFile(entity.Name + ".cs");
    BeginNamespace(code);
#>
//START MODIFICATION
using System.Runtime.Serialization;
<#=codeStringGenerator.UsingDirectives(inHeader: false)#>
<#
    var propertiesWithDefaultValues = typeMapper.GetPropertiesWithDefaultValues(entity);
    var collectionNavigationProperties = typeMapper.GetCollectionNavigationProperties(entity);
    var complexProperties = typeMapper.GetComplexProperties(entity);

    foreach (var navigationProperty in collectionNavigationProperties)
    
#>
[KnownType(typeof(<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>))]
<#
    
#>
<#=codeStringGenerator.EntityClassOpening(entity)#>

<#
    if (propertiesWithDefaultValues.Any() || collectionNavigationProperties.Any() || complexProperties.Any())
    
#>
    public <#=code.Escape(entity)#>()
    
//END MODIFICATION
<#
        foreach (var edmProperty in propertiesWithDefaultValues)
        
#>
        this.<#=code.Escape(edmProperty)#> = <#=typeMapper.CreateLiteral(edmProperty.DefaultValue)#>;
<#
        

        foreach (var navigationProperty in collectionNavigationProperties)
        
#>
        this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
<#
        

        foreach (var complexProperty in complexProperties)
        
#>
        this.<#=code.Escape(complexProperty)#> = new <#=typeMapper.GetTypeName(complexProperty.TypeUsage)#>();
<#
        
#>
    

【讨论】:

以上是关于具有子集合的实体在 WCF 中导致问题:如果您使用 DataContractSerializer,请考虑使用 DataContractResolver的主要内容,如果未能解决你的问题,请参考以下文章

WPF TreeView HierarchicalDataTemplate - 绑定到具有多个子集合的对象

在 Firestore 中删除包含所有子集合和嵌套子集合的文档

具有EF6子集合的父/子总是为空

读取带有子集合的文档的 Firestore 计费

Cloud Firestore 如何查找包含特定文档 ID 的子集合的所有文档?

updateOrCreate 在 laravel 中导致 ErrorException