【问题标题】:Does it make sense to map an object to another object of the same type?将一个对象映射到另一个相同类型的对象是否有意义?
【发布时间】:2016-07-14 15:05:17
【问题描述】:

我正在使用 Entity Framework 6 并将我的查询结果从 WCF 服务中发送出去。如果我尝试发送查询返回的实体,由于动态代理,我会收到异常。

我之前的解决方法是使用这样的代码...

return PatientServiceLogic.GetAll()
  .Select(p => new Patient {
    ID = p.ID,
    FirstName = p.FirstName,
    Surname = p.Surname,
    AccidentDate = p.AccidentDate
  })
  .ToList();

这是一个简化的例子。可以想象,当对象图增长时,这可能会相当痛苦。

我刚刚发现了 AutoMapper,它看起来可以为我节省大量样板代码。当我想发送一组 Patient 对象(将在客户端应用程序的网格中使用)时,我不想要完整的 Patient 对象图,我想要一个简化的扁平版本。为此,PatientDto 类就可以了。

但是,假设我确实想要发送完整的对象图。我认为创建 Patient 类和所有相关类的副本,然后将一个副本复制到另一个,只是为了能够将它们发送出去,这没有任何意义。重用 EF 生成的类,并将 Patient 对象映射到一个新的 Patient 对象(在代码中创建,而不是 EF)没有动态代理会更有意义。这基本上就是我上面的代码正在做的事情。

我试过这个,但我得到了无用且非描述性的异常显示在下方。

任何人都有cmets吗?这甚至是明智的做法吗?如果没有,处理这种情况的最佳方法是什么?

这是我在尝试使用MapperConfiguration(c => c.CreateMap<Patient, Patient>()) 设置的映射调用服务时从 WCF 测试客户端得到的异常

接收到http://localhost:5448/PatientsService.svc 的 HTTP 响应时出错。这可能是由于服务端点绑定未使用 HTTP 协议。这也可能是由于服务器中止了 HTTP 请求上下文(可能是由于服务关闭)。有关详细信息,请参阅服务器日志。

服务器堆栈跟踪:

在 System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest 请求, HttpAbortReason abortReason)
在 System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan 超时)在 System.ServiceModel.Channels.RequestChannel.Request(消息消息, TimeSpan 超时)在 System.ServiceModel.Dispatcher.RequestChannelBinder.Request(消息 消息,TimeSpan 超时)在 System.ServiceModel.Channels.ServiceChannel.Call(字符串动作, Boolean oneway, ProxyOperationRuntime 操作, Object[] ins, Object[] 出局,TimeSpan 超时)在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall,ProxyOperationRuntime 操作)在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage 留言)

在 [0] 处重新抛出异常:在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(消息数据& msgData,Int32 类型)在 PatientService.GetPatients() 在 PatientServiceClient.GetPatients()

内部异常:

底层连接已关闭:发生意外错误 一个接收。在 System.Net.HttpWebRequest.GetResponse() 在 System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan 超时)

内部异常:

无法从传输连接读取数据:现有 连接被远程主机强行关闭。在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量, Int32 大小)在 System.Net.PooledStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 大小)在 System.Net.Connection.SyncRead(HttpWebRequest 请求,布尔值 userRetrievedStream, Boolean probeRead)

内部异常:

一个现有的连接被远程主机强行关闭 System.Net.Sockets.Socket.Receive(Byte[] 缓冲区,Int32 偏移量,Int32 大小,SocketFlags socketFlags)在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量, int32 大小)

【问题讨论】:

  • 问题“为什么我们在跨层时使用数据传输对象而不是我们的实体类”已经被讨论死了。您的研究表明了什么,您希望那个问题得到回答,还是要解决异常?
  • @CodeCaster 实际上,我没有这样想。我将 EF 生成的类视为 POCO(如果您查看代码,它们似乎是),并在 EF 创建它们时在顶部添加了代理。我假设(可能是错误的)当您自己创建它们时(如var p = new Patient()),那么您将获得没有代理的 POCO。从这个角度来看,创建相同的 DTO 似乎毫无意义。请你澄清一下,因为我不确定我在哪里想错了。
  • @CodeCaster 有什么意见吗?我该怎么做?有人可以评论吗?

标签: c# wcf automapper


【解决方案1】:

您当前的问题似乎是您的数据库连接在您完成数据处理之前已关闭。

尝试使用

db.mainEntity.Include(i=>i.relatedtable).Include(i=>i.anotherRelatedtable)

在您对所有相关实体的查询中。

不要在序列化程序中制作对象的一对一副本的一个很好的理由是循环(您之前可能在使用 json-feeded 组件时已经解决了它们):

父亲有孩子,孩子有父亲,父亲有孩子,他有……溢出!

【讨论】:

  • 感谢您的回复,但它有什么帮助?所有相关实体都已加载,所以我不确定 using .Include() 会添加什么。我的根本问题(这不是我在这个问题中要解决的问题)是关联实体在连接关闭之前不会被加载。为了避免这种情况,我需要能够告诉查询不要包括哪些关联实体。请你澄清一下。
  • 如果启用了急切加载。实体仅在引用时才会加载相关元素。我已经尝试过了,但是,如果您的对象在内存中,我不确定 EF 会在您尝试访问它们之前分配子元素。使用“包含”应该强制在您进行查询时更新这些关系。当然,您必须在连接关闭之前询问结果,因此请在退出上下文的 using 语句或范围之前尝试对结果集执行 ToList()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 2013-04-13
  • 1970-01-01
相关资源
最近更新 更多