具有子集合的实体在 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 中删除包含所有子集合和嵌套子集合的文档