好的,所以我在创建DTO以通过电线发送我的模型的漫长过程中处于中途,我不觉得我走的是正确的路线。
我的问题是,我的模型中的大多数实体并不比DTO更多。我基本上有一个贫血的领域模型,这很好,但它也让我想知道我是否需要为这些实体建模DTO。
所以我的第一个问题是,如果只是序列化我的实体并通过网络传递这些问题,我会遇到什么问题?
其次,一个更具体的问题给出了如下属性签名:
public virtual Unit Unit { get; set; }
我可以通过线路发送UnitId而不是序列化的单元对象吗?
修改: 对不起我对我的问题不够清楚,因为你们发布了我知道我只能指定单位的Id属性,但这对我不起作用。
原因是这个属性(上面)位于“Country”类上,我希望UnitID仅在我调用“CountryService.GetCountry(Id)”或simmilar时返回。但是在floowing服务调用“UnitService.GetUnit(Id)”中,我希望通过网络序列化和发送更多属性。 希望这是有道理的。
谢谢,克里斯。答案 0 :(得分:1)
其次,一个更具体的问题给出了如下属性签名:
public virtual Unit Unit { get; set; }
我是否可以通过电线发送UnitId和 不是序列化的单位对象?
当然 - 确保
Unit
[DataMember]
媒体资源
UnitId
的第二个属性,您执行标记为数据成员Unit
课程UnitId
更新:
原因是这个属性 (上)是在“国家”级和我 希望UnitID仅在我返回时返回 调用“CountryService.GetCountry(Id)” 或者类似的。但是在飞行中 服务调用“UnitService.GetUnit(Id)” 我想要更多的属性 序列化并通过电线发送。 希望这是有道理的。
在这种情况下,您需要两个单独的DataContracts - 一个用于CountryService.GetCountry(Id)
调用,其中只包含UnitId
,另一个用于UnitService.GetUnit(Id)
调用,其所有属性均为{ {1}}你想要它。
根据运行时的决定,您无法有条件地发送某些属性 - 或者不发送。 DataContracts以XML模式建模,这是非常静态的。如果您有两组需要的属性,则需要两个单独的DataContracts。
答案 1 :(得分:0)
您可以通过添加NonSerializedAttribute(msdn)来缩小将通过网络传递的对象。您仍将获得Unit,但仅限于UnitId。
我不认为只是序列化你的DTO会有问题。 您是否使用了DTO中的所有信息? 你跨越域名边界?我会在每个域中创建新实体并为它们制作映射器。
答案 2 :(得分:0)
根据我的理解,您的问题源于您有一个由您的DTO制作的本地显式声明的对象图。我的意思是你已经在你的public Unit Unit { get; set; }
模型上声明Country
(不确定为什么你宣布它们virtual
但这与手头的问题没有直接关系)而不是尝试保证对象图简单到单个对象图节点的退化情况的方法。
例如,考虑在public UnitID Unit { get; set; }
形式的模型中定义每个“reference”属性,其中UnitID
可能实际为int
或{{1}或者你用来唯一地识别和区分Guid
模型的任何东西。只要您有对另一个模型的引用或引用集,请将其替换为其标识符类型而不是其实际类型。这种策略很适合一组持久的模型,例如:从/到具有每个模型的标识键的数据库。这样做可以简化序列化,而不必担心循环引用,因为它们现在是不可能的。从技术上讲,没有更多的引用(即直接引用;它们现在是间接引用)。我们现在只是在您的域模型设计中添加一层间接。现在让我们适应那个间接层。
既然你声称你对贫血领域模型方法很好,那么这应该与之相符。您在模型设计中支付次要(IMHO)间接成本,并将其换成基于接口的数据检索方法的主要(IMHO)优势:
Unit
在您的消费者代码中(即使用此接口的代码和您的public interface IUnitRepository {
Unit GetUnit(UnitID id);
IEnumerable<Unit> GetUnits(IEnumerable<UnitID> ids);
// etc.
}
域模型),通过执行接口调用以获取指向的基础模型,遍历隐含对象图只会稍微复杂一些。间接参考。
在:
Unit
在:
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit;
如果这在语法上困扰你,你可以定义一个在表单的// Somewhere earlier in your code, i.e. not *every* time this type of code appears
IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = repo.GetUnit(ct.UnitID);
上键入的扩展方法:
Country
扩展方法后:
public static Unit Unit(this Country c, IUnitsRepository repo) {
return repo.GetUnit(c.UnitID);
}
基于接口的方法为您提供了一系列经典优势,例如关注点分离,可测试性,消费者 - 生产者绝缘等等。此外,您现在可以通过接口的实现类型更直接地控制对象的生命周期。我的意思是你不应该假设你的IUnitsRepository repo = new SomeUnitsRepositoryImpl();
Country ct = ...; // I assume you have this reference already
Unit ut = ct.Unit(repo);
方法的实施是天真的。此方法现在可以使用与Unit GetUnit(UnitID id)
实例绑定的Dictionary<UnitID, Unit>
执行一些本地内存缓存。
有点啰嗦,但我希望它有所帮助。好像从提供的细节数量来看并不明显,我目前正在我的工作场所使用这种设计处理我们的记录数据库系统。 :)我非常喜欢它给我所有的灵活性,只需在领域模型的设计中添加一个间接级别的简单成本。