在客户端/服务器应用程序中将DTO对象图映射回实体框架对象图的优雅方式

本文关键字:对象图 框架 实体 方式 映射 服务器 应用程序 DTO 客户端 | 更新日期: 2023-09-27 18:30:12

我有一个客户端/服务器应用程序,其中服务器使用实体框架作为ORM。要发送到客户端的每个实体都由一个DTO类表示。

实体框架和DTO类之间的映射是使用AutoMapper处理的。

假设我们有以下表格:

人员(字符串名称,int CountryID)国家(int CountryID,int人口,字符串名称)

它们由以下EF类表示:

class Person
{
 public string Name { get; set; }
 public int CountryID { get; set; }
 public Country Country { get; set;}
}
class Country
{
 public int CountryID { get; set; }
 public int Population { get; set; }
 public string Name { get; set;}
}

依次由以下DTO表示:

class PersonDTO
{
 public string Name { get; set; }
 public CountryDTO Country { get; set;}
}
class CountryDTO
{
 public int CountryID { get; set; }
 public int Population { get; set; }
 public string Name { get; set;}
}

数据库的初始状态表示一个空的Person表和一个Country表,该表有一个条目:(1123,"CountryXYZ")

客户的应用程序任务是创建一个新的个人实体,并将其国家/地区参考附加到可用的"CountryXYZ"国家/地区实体。

为此,客户端应用程序首先请求可用的CountryDTO。然后,它创建一个新的PersonDTO实例,并将其Country属性设置为从服务器接收到的唯一CountryDTO。然后将这个PersonDTO实例发送回服务器。服务器反过来将PersonDTO实例映射回Person实例。

服务器的最后一步是将Person实例存储在ObjectContext中,并调用ObjectContext.SaveChanges().

这种方法的问题是,一旦我调用ObjectContext.SaveChanges(),就会在数据库中创建一个新的Country行,而不仅仅是使用可用的Country。我在这里错过了什么?

我是EF的新手,我认为这个用例很常见。。。所以我希望有一个简单的解决办法。

如果问题描述不够清楚,请告诉我。

谢谢!

在客户端/服务器应用程序中将DTO对象图映射回实体框架对象图的优雅方式

如果您知道客户端将始终使用它已经从您的服务器收到的国家/地区(它是现有的),您可以简单地修改您的保存逻辑以使用:

objectContext.PersonSet.AddObject(personToSave);
objectContext.ObjectStateManager
             .ChangeObjectState(personToSave.Country, EntityState.Unchanged);
objectContext.SaveChanges();

如果使用AddObject方法,则实体及其所有关系都标记为已添加,并且将作为新对象插入数据库,除非重新配置它们的状态。

实体还公开FK属性,以便在将DTO映射回实体而不是创建国家/地区实例时可以使用FK属性。在这种情况下,您将不需要处理关系状态的更改,因为该关系将仅通过integer列表示。

如果客户端可以在一次调用中同时创建PersonCountry,您将需要DTO中的一些标志来区分现有实体或新实体,或者您必须查询数据库以验证此类Country是否已经存在。

这是一个使用自跟踪实体可能对您有用的实例。

它使用T4模板来生成实体类,并且它们可以使用WCF跨线往返。但是,您需要共享包含客户端和服务器上实体的程序集。

如果你同时控制两者,并且两者都使用.Net,我会走这条路。