我一直在尝试使用AutoMapper来节省从我的DTO到我的域对象的时间,但是我在配置地图时遇到了麻烦,以至于它工作正常,我开始怀疑AutoMapper是否可能是错误的工具工作.
考虑这个域对象的例子(一个实体和一个值):
public class Person
{
public string Name { get; set; }
public StreetAddress Address { get; set; }
}
public class StreetAddress
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我的DTO(来自Linq-to-SQL对象)的出现大致如下:
public class PersonDTO
{
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; } …
Run Code Online (Sandbox Code Playgroud) 我的ASP.NET MVC3/NHibernate应用程序需要触发和处理与我的域对象相关的各种事件.例如,Order
对象可能包含OrderStatusChanged
或等事件NoteCreatedForOrder
.在大多数情况下,这些事件会导致发送电子邮件,因此我不能将它们留在MVC应用程序中.
我已经阅读了Udi Dahan的Domain Events以及关于如何做这类事情的许多其他想法,我决定使用一个处理事件消息的基于NServiceBus的主机.我做了一些概念验证测试,这似乎运作良好.
我的问题是应用程序层应该实际引发事件.我不想在有问题的对象成功保留之前触发事件(如果持久性失败,则无法发送创建注释的电子邮件).
另一个问题是,在某些情况下,事件与聚合根下面的对象相关联.在上面的示例中,Note
通过将a 添加到Order.Notes
集合并保存订单来保存a .这带来了一个问题,因为它很难评估Order
保存时应该触发哪些事件.我想避免在保存更新的副本之前必须拉出对象的当前副本并查找差异.
用户界面提出这些事件是否合适?它知道发生了什么事件,并且只有在成功使服务层保存对象后才能触发它们.让控制器触发域事件似乎有些不对劲.
存储库是否应该在成功持久后触发事件?
我是否应该完全分离事件,让存储库存储一个Event
对象,然后由轮询器服务接收该对象,然后将其转换为NServiceBus的事件(或直接从轮询器服务处理)?
有一个更好的方法吗?也许让我的域对象排队只有在持久化对象后由服务层触发的事件?
更新:我有一个服务层,但让它通过比较过程以确定在保存给定聚合根时应该触发哪些事件似乎很麻烦和过分.由于其中一些事件是粒状的(例如"订单状态已更改"),我认为我必须检索对象的数据库副本,比较属性以创建事件,保存新对象,然后将事件发送到NServiceBus保存操作成功完成.
在我下面发布的答案(下面的方法)之后,我最终做的是在我的域实体中构建一个EventQueue
属性List<IDomainEvent>
.然后我添加了事件,因为对域的更改是值得的,这使得我可以将逻辑保留在域中,我认为这是合适的,因为我根据实体内部的内容触发事件.
然后,当我将对象保留在服务层中时,我处理该队列并实际将事件发送到服务总线.最初,我计划使用使用身份PK的遗留数据库,因此我必须对这些事件进行后处理以填充实体的ID,但我最终决定切换到Guid.Comb
允许我跳过该步骤的PK.
asp.net-mvc domain-driven-design nservicebus domain-events asp.net-mvc-3
我刚刚开始使用DDD,我在确定如何适应数据的关系性质方面遇到了一些麻烦.我有我认为会被视为我的聚合根,但聚合也有自己的聚合.我不想违反德米特法则,我想知道我是否正在考虑这个错误,并希望一些DDD专家可以提供一些见解.
我的聚合根是我的Account
对象,它有许多AccountElement
实体的集合,它们本身就是各个ProductComponent
实体的逻辑分组.
一个AccountElement
的上下文之外Account
已经没有任何意义,所以我很舒服,我的结论是,Account
对象是我聚合根,我预计其总实体Elements
属性.这是让ProductComponent
我感到困惑的系列.该集料具有外没有任何意义AccountElement
,而真正具有的外部没有任何意义Account
.
我认为我不应该通过点击它来访问单个ProductComponent
对象,例如:
var reference = account.Elements(0).ProductComponents(0).ReferenceCode;
Run Code Online (Sandbox Code Playgroud)
但与此同时,(从域的角度来看)ProductComponent
直接从Account
实体访问是没有意义的.
我确信如果不了解我的域名,这有点难以理解,但我希望这足以得到一些好的反馈.
我正在使用表单的AutoComplete UI小部件来允许用户键入客户名称.我们的想法是,他们可以选择现有客户并填充表单中的其他字段,也可以自由键入要创建的新客户.当用户选择现有客户时,我使用该select
事件填充隐藏输入以存储与该客户关联的ID.
我遇到的问题是,如果用户首先从列表中选择一个客户,然后进入并编辑文本,实际上创建了一个新客户,我需要能够清除隐藏的输入ID值.
我提到了这个问题并创建了以下代码:
$(function() {
$("#customerName").autocomplete({
source: "/Customers/CustomerListJSON",
minLength: 2,
select: function(event, ui) {
$("#customerId").val(ui.item ? ui.item.Id : "");
},
change: function(event, ui) {
try {
$("#trace").append(document.createTextNode(event.originalEvent.type + ", "));
if (event.originalEvent.type != "menuselected")
$("#customerId").val("");
} catch (err) {
$("#customerId").val("");
}
}
});
});
Run Code Online (Sandbox Code Playgroud)
问题是更改事件被触发blur
,因此如果用户选择了一个客户,则会填充隐藏的输入值,但只要他们将焦点从输入框移开,就会立即清除它.但是,如果我blur
从event.originalEvent.type
测试中排除事件,则隐藏字段的值永远不会在用户编辑先前选择的值的原始方案中重置.
有没有人必须先解决这个问题,如果是这样的话,你可以提供一些关于我如何管理隐藏输入值的指导,这样只有当从列表中选择一个项目并用任何其他值清除时才会填充它?
我为64位IIS7/Win2008上运行的ASP.NET MVC2应用程序创建了一个app_offline.htm文件,并确保它超过512字节(现在是2KB).在我运行Visual Studio 2010的开发盒上,它就像一个魅力,但当我把它放在生产盒上时,我得到的只是通用的HTTP 500错误,说"由于发生内部服务器错误,页面无法显示".
特别奇怪的是,我没有在应用程序事件日志中记录任何内容,ELMAH也没有选择任何内容.我已经禁用了自定义错误,为文件放置了FormsAuthentication位置异常,确保我没有引用任何其他文件(图像等),但没有任何修复它.
我已经阅读了关于SO和谷歌搜索的每个帖子几个小时,无法弄清楚这一点.什么想法可能是错的?我把头发拉到这里......
我在Instant
ServiceStack 的 DTO 中使用 NodaTime进行日期/时间存储。我已将 DTO 中的 SQL 类型指定为datetimeoffset
,ServiceStack 正确创建了具有该类型的表。但是,在保存时,我得到一个InvalidCastException
.
简单的例子:
public class ItemWithInstant
{
public int Id { get; set; }
public string Name { get; set; }
[CustomField("DateTimeOffset")
public Instant DateCreated { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在服务中:
public object Post(CreateItemWithInstant request)
{
var dto = request.ConvertTo<ItemWithInstant>();
Db.Save(dto); // ERROR here
return dto;
}
Run Code Online (Sandbox Code Playgroud)
具体的错误是一个InvalidCastException带有Failed to convert parameter value from an Instant to a String 的详细信息。
不知道为什么当数据库类型为DateTimeOffset
. 我是否需要告诉 …
我有一个Notes
带有uniqueidentifier
列的表,我用它作为数据库中各种其他表的FK(不用担心,uniqueidentifier
其他表上的列不是集群PK).这些其他表表示业务对象层次结构的某些内容.作为一个简单的表示,假设我还有另外两个表:
在Lead
应用程序中显示a 时,我需要显示与潜在客户相关的所有注释,包括标记为任何Quote
属于该潜在客户的注释.据我所知,我有两个选择 - 一个UNION ALL
或几个LEFT JOIN
语句.这是他们看起来的样子:
SELECT N.*
FROM Notes N
JOIN Leads L ON N.TargetUniqueID = L.UniqueID
WHERE L.LeadID = @LeadID
UNION ALL
SELECT N.*
FROM Notes N
JOIN Quotes Q ON N.TargetUniqueID = Q.UniqueID
WHERE Q.LeadID = @LeadID
Run Code Online (Sandbox Code Playgroud)
要么...
SELECT N.*
FROM Notes N
LEFT JOIN Leads L ON N.TargetUniqueID = L.UniqueID
LEFT JOIN Quotes Q …
Run Code Online (Sandbox Code Playgroud) 当谈到具有现代ORM的分层应用程序时,我常常不确定如何创建特定类以遵守所谓的"最佳实践",同时还要关注性能要求.
考虑到应用程序中可能包含以下任意类型的对象:
域实体 - 这些是包含业务逻辑的丰富类(对吗?),并且根据ORM功能,可能与持久性设计直接相关.
DTO - 这些是更简单的类,它们剥离业务逻辑,以便将数据传递给内部和外部客户端.有时这些是扁平化的,但并非总是如此.
视图模型 - 这些与DTO类似,因为它们更简单,没有业务逻辑,但它们通常非常扁平,并且通常包含与它们所服务的UI相关的其他位.
我遇到的挑战是,在某些情况下,域实体或任何面向持久性的类映射到更简单的实体(如DTO或ViewModel)会阻止您进行重要的性能优化.
假设我有一些域实体看起来像这样:
public class Event
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime EventDate { get; set; }
// These would be reference types in most ORMs
// Pretend in the setter I have logic to ensure the headliner =/= the opener
public Band Headliner { get; set; }
public Band Opener { get; set; }
}
public class …
Run Code Online (Sandbox Code Playgroud) 几天前我以一种更加冗长的方式问过这个问题,考虑到长度,我得不到答案的事实并不令人惊讶,所以我认为我会更加注重这一点.
我必须根据对特定客户的分配来决定显示用户的内容.域对象看起来像这个极其简化的示例:
public class Customer
{
public string Name { get; set; }
public IEnumerable<Users> AssignedUsers { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在现实世界中,我还将评估他们是否具有权限(使用安全标志的按位比较)来查看此特定客户,即使他们没有直接分配给它.
我在这里试图坚持域驱动设计(DDD)原则.另外,我正在使用LINQ to SQL进行数据访问.在我的服务层,我提供请求客户列表的用户,现在大约有1000个项目,每月增长约2%.
如果我严格要求在我的服务层中保留逻辑,我将需要使用Linq来.Where
评估AssignedUsers
列表是否包含请求列表的用户.这将导致Customer
系统枚举的每个查询级联.我没有做任何测试,但这似乎效率低下.
如果我捏造数据中的无逻辑,那么我可以简单地使用一种GetCustomersByUser()
方法来执行一种EXISTS
SQL查询并同时评估安全性.这肯定会更快,但现在我在谈论逻辑爬进数据库,这可能会在以后产生问题.
我敢肯定,这是人们在推出Linq时提出的一个常见问题...任何关于哪种方式更好的建议?Linq的多个查询的性能是否优于我的数据库中的逻辑?
我正在尝试实现IUserType
状态和国家/地区代码,这将允许我访问两个字母的代码(存储在数据库中的代码)以及全名.我正在关注NHibernate 3.0 Cookbook中的示例(p.225),但我的问题是我的StreetAddress
类当前被映射为我的自动配置中的一个组件:
public override bool IsComponent(Type type)
{
return type == typeof(StreetAddress);
}
Run Code Online (Sandbox Code Playgroud)
将此类标识为组件,我不知道如何使用IUserType
组件类的属性,因为该类未显式映射.我无处可以告诉流利的NHibernate使用IUserType
规范.
c# ×3
asp.net-mvc ×2
architecture ×1
asp.net ×1
autocomplete ×1
automapper ×1
iusertype ×1
jquery-ui ×1
linq-to-sql ×1
mapping ×1
nhibernate ×1
nodatime ×1
nservicebus ×1
performance ×1
servicestack ×1
sql-server ×1
t-sql ×1