【发布时间】:2011-12-15 15:24:15
【问题描述】:
伙计们!
假设我们有一组呈现问题域的接口:IUser, IAddressBook, IComment 等等。假设IUser 定义如下:
public interface IUser : IAmIdentifiedEntity<int>, IHaveName
{
string FullName { get; set; }
string Email { get; set; }
bool ReceiveNotification { get; set; }
}
public interface IHaveName
{
string Name { get; set; }
}
在我的应用程序中,我只使用提到的合约,例如:
public IUser GetUser(string userName)
{
return Warehouse.GetRepository<IUser>().GetAll()
.First(u => u.Name == userName);
}
如您所见,我正在使用一些网关来获取数据。 Repository 的方法GetAll() 返回IQueryable<TEntity>,因此可以构建一些复杂的查询并使用延迟加载的所有好处。在介绍的时候,我想到了 Linq2Sql 以后的应用。
有一段时间,在开发客户端代码时,我们一直在使用“内存中”实现数据存储。所以一切正常。但现在是时候将域绑定到 SQL Server 了。所以我开始在 Linq2Sql 上实现所有基础设施......当制作简单的解决方案(受 Fredrik Kalseth 的 article 启发)并遇到第一个异常时,我意识到了所有的悲伤想法...这是IUser的实现:
public partial class USER : IUser
{
int IHaveID<int>.ID
{
get { return USERID; }
}
string IHaveName.Name
{
get { return USERNAME; }
set { USERNAME = value; }
}
string IUser.FullName
{
get { return USERFULLNAME; }
set { USERFULLNAME = value; }
}
// ... same approach for other properties
}
这里 - 例外:
Exception: System.NotSupportedException:
The member 'Data.IHaveName.Name' has no supported translation to SQL.
这是一个明显的例外——Linq2Sql 提供者不理解外部接口,但我应该如何解决呢?我无法更改域接口以返回 Linq.Expression,例如:
Expression<Func<string>> IHaveName.Name
{
get { return (() => USERNAME); }
set { USERNAME = value(); }
}
因为它破坏了域接口的所有当前代码使用,而且由于宗教信仰,我不能用 Expression<Func<int>> 替换 int :)
也许,我应该编写自定义表达式访问者以跳过 IUser.SomeProperty 的查询 AST 调用并将其替换为它的内部子 AST...
你能提供你的想法吗?
更新。 在这里我应该写一些关于Repository 实现的内容。看GetAll()来源:
public IQueryable<TEntity> GetAll()
{
ITable table = GetTable();
return table.Cast<TEntity>();
}
protected ITable GetTable()
{
return _dataContext.GetTable(_implType);
}
在我的示例中,TEntity <=> IUser 和 _implType <=> typeof(USER)
更新 2. 我发现 related question,其中 OP 有一个类似的问题:需要在具体的 ORM 实体和它的域实体之间建立一些桥梁。而且我发现了有趣的the answer:作者建议创建表达式访问者,它将执行实体之间的转换(ORM 域)。
【问题讨论】:
标签: c# linq linq-to-sql domain-driven-design ddd-repositories