我一直在复习我的设计模式,并发现我无法在任何地方找到好的答案。所以也许有更多经验的人可以帮助我。
DAO 模式是否仅用于访问数据库中的数据?
我发现的大多数答案都暗示是;事实上,大多数关于 DAO 模式的谈话或写作往往会自动假设您正在使用某种数据库。
不过我不同意。我可以有一个如下的 DAO:
public interface CountryData {
public List<Country> getByCriteria(Criteria criteria);
}
public final class SQLCountryData implements CountryData {
public List<Country> getByCriteria(Criteria criteria) {
// Get From SQL Database.
}
}
public final class GraphCountryData implements CountryData {
public List<Country> getByCriteria(Criteria criteria) {
// Get From an Injected In-Memory Graph Data Structure.
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我有一个 DAO 接口和 2 个实现,一个与 SQL 数据库一起使用,一个与内存中图形数据结构一起使用。这样对吗?或者图形实现是要在其他类型的层中创建的?
如果它是正确的,那么抽象每个 DAO 实现所需的实现特定细节的最佳方法是什么?
例如,采用上面的 Criteria Class I 参考。假设它是这样的:
public final class Criteria {
private …Run Code Online (Sandbox Code Playgroud) 关于设计合适的 DAO 的讨论总是如此流行,其结论总是“DAO 应该只执行简单的 CRUD 操作”。
那么执行聚合等操作的最佳位置是什么?DAO 是否应该返回类似于数据源架构的复杂对象图?
假设我有以下 DAO 接口:
public interface UserDao {
public User getByName(String name);
}
Run Code Online (Sandbox Code Playgroud)
这是它返回的对象:
public class Transaction {
public int amount;
public Date transactionDate;
}
public class User {
public String name;
public Transaction[] transactions;
}
Run Code Online (Sandbox Code Playgroud)
首先,我认为如果 DAO 所做的只是 CRUD 操作,那么它会返回一个标准值对象。
所以现在我已经通过 DAO 建模来返回基于数据存储关系的东西。它是否正确?如果我有更复杂的对象图怎么办?
更新:我想我在这一部分中要问的是,DAO 的返回值(无论是 VO、DTO 还是任何您想要的名称)是否应该按照数据存储的数据表示进行建模?或者我应该引入一个新的 DAO 来获取用户的交易,并为 UserDAO 拉取的每个用户调用 TransactionDAO 来获取它们?
其次,假设我想对用户的所有交易执行聚合。使用这个 DAO,我可以简单地获取一个用户,并在我的服务循环中遍历事务数组并自己执行聚合。毕竟,说这样的聚合是属于服务的业务规则是完全合理的。
但如果用户的交易数量达到数万怎么办?这会对应用程序性能产生负面影响。在 DAO 上引入一种执行上述聚合的新方法是否不正确?
当然,这可能是假设 DAO 由数据库备份,我可以在其中编写简单的 SELECT SUM() 查询。如果 DAO 实现更改为平面文件或其他内容,我无论如何都需要在内存中进行聚合。
那么这里的最佳实践是什么?
我不能为我的生活弄清楚这一点.假设我有以下两个字典对象:
// Assume "query" is a LINQ queryable.
Dictionary<string, int> d1 = query.ToDictionary(k => k.Key, v => v.Value);
Dictionary<string, int> d1 = query.ToDictionary(k => k.Key, v => v.Value);
Run Code Online (Sandbox Code Playgroud)
以下语句产生编译时错误,无法在Dictionary和IDictionary之间进行隐式转换:
// Compile time error!
Tuple<IDictionary<string, int>, IDictionary<string, int>> = Tuple.Create(d1, d2);
Run Code Online (Sandbox Code Playgroud)
我必须明确地进行转换:
Tuple<IDictionary<string, int>, IDictionary<string, int>> = Tuple.Create(d1 as IDictionary<string, int>, d2 as IDictionary<string, int>);
Run Code Online (Sandbox Code Playgroud)
我不明白为什么编译器无法弄清楚协方差操作 - Dictionary实现了IDictionary - 特别是因为像这样的东西当然会起作用我们都知道:
IDictionary<string, int> d3 = d1;
Run Code Online (Sandbox Code Playgroud)
我确信这种行为有充分的理由,我很好奇它是什么.
更新1: 只是为了澄清,我很好奇行为不是如何解决问题.我知道不同的解决方案:)
更新2:
谢谢大家的答案.我不知道Tuple是不变的,现在我做了.
我不能为我的生活弄清楚这一点.MSDN上的文章不清楚,似乎已经过时了.我正在使用EF 5,我正在尝试为以下内容建立单向关系.所以这就是我到目前为止所拥有的.
public sealed class Capture {
/// <summary>
/// Get and Set Capture's Unique Identifier.
/// </summary>
public int Id { get; set; }
/// <summary>
/// Get and Set Capture's Operating System.
/// </summary>
public OperatingSystem OperatingSystem { get; set; }
}
public sealed class OperatingSystem {
/// <summary>
/// Operating System's Unique Identifier.
/// </summary>
public int Id { get; set; }
}
internal sealed class EntityCaptureConfiguration : EntityTypeConfiguration<Capture> {
/// <summary>
/// Create an Entity Capture …Run Code Online (Sandbox Code Playgroud) 所以,我在WinForms中遇到了这个问题,至少我认为这是一个问题,我无法弄清楚如何解决它.
基本上,当我Validating为控件实现事件处理程序时,我CancelEventArgs.Cancel在控件未通过验证时将其设置为true.示例代码:
private void NameTextBox_Validating(object sender, CancelEventArgs e) {
// Assume Cool Validation Logic.
//
// ...
var isValid = false;
if (!isValid) {
e.Cancel = true;
// Set an Error Provider Message.
//
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这会导致整个UI挂起.我无法选择任何其他控件,最小化父窗体窗口,或事件退出父窗体窗口.所以我找到了一个类似的问题,其答案建议FormClosing为父表单实现一个事件处理程序,并FormClosingEventArgs.Cancel在那里设置为false.
问题是,只要我的控件无效,就不会调用该事件处理程序.我觉得它可能与我的控制层次结构有关,尽管我不是100%肯定.如果这有助于它:
-- Parent Form
---- Custom User Control
------ Text Box Control (<-- Causes Hang)
Run Code Online (Sandbox Code Playgroud)
任何想法将不胜感激.
一直在玩这个几个小时,似乎无法理解它.
在Wicket中,List Choice采用一组模型来表示构成列表的选项.当提交添加列表选择的表单时,Wicket将所选选项的模型绑定到表单的模型.
但是如果我不希望整个模型绑定而是特定属性呢?
例如:
public class FormModel {
private int locationId;
public void setLocationId(int id) {
this.locationId = id;
}
}
public class LocationModel {
private int id;
public int getId() {
return this.id;
}
}
<select wicket:id="LocationId" id="LocationId" name="LocationId" size="1">
<option value="#">#</option>
</select>
Run Code Online (Sandbox Code Playgroud)
提交表单时,Wicket将尝试将整个LocationModel绑定到FormModel,显然我只想绑定它的locationId属性.
我已经在使用ChoiceRenderer但这似乎仅在表单呈现时才提交.
结果是一个终极类强制转换异常,因为Wicket将无法将LocationModel转换为整数.
我不想为表单创建另一个模型来接受LocationModel.
有什么想法吗?
仍然阅读和学习DDD并尝试将其应用于我正在进行的项目.我仍然试图绕过Aggregates并遇到一个有趣的问题.
假设我有2个聚合,1个拥有root用户实体,另一个用户实体用于root用户.
没有用户但用户可以创建帐户,这就是为什么它们都作为自己的聚合的根.注意,它们的聚合包括其他实体,但这对我的问题并不重要.
一些业务规则:1)创建帐户时,它必须与用户关联.如果用户不存在,则必须先创建它.
2)删除帐户时,还必须删除其关联的用户.
3)创建用户时,不需要与帐户关联.
3)删除用户时,如果与帐户关联,则也必须删除.
由于帐户和用户形成自己的聚合,因此可能会有自己的存储库.这意味着每个存储库都将定义标准的Add,Delete,Find和Delete方法.
因此,在这些情况下,完成以下操作的最佳方法是:1)创建帐户时,我想我会在其用户属性上调用一个方法来验证用户确保它存在.这是正确的吗?
2)删除帐户时,如何删除其关联的用户.从帐户Repoistory?但这不只是重复用户存储库中的代码吗?或者存储库可以引用并互相调用吗?
3)当用户被删除时,最好的方法是确定它是否与帐户相关联并删除它而没有代码重复(可能与第二个问题类似).
我在某处读到如果逻辑跨越两个实体或聚合,请考虑使用服务.但我对此并不满意,因为什么阻止了客户端(假设API将在不断发展,用户将来还有其他演示文稿)绕过服务并只是调用存储库?
更新1:
刚刚意识到这可能是一个相关的问题:我应该如何在聚合根之间强制实现关系和约束?
java domain-driven-design repository aggregateroot aggregates
java ×4
.net ×3
c# ×3
dao ×2
.net-4.5 ×1
aggregates ×1
apache ×1
covariance ×1
dto ×1
repository ×1
wicket ×1
winforms ×1