C# 通用表<;张力>;
尝试将LINQtoSQL用于我正在家里进行的一个小项目。我已经使用dbmetal.exe(来自DBLinq项目)针对本地MySQL数据库生成了一个上下文代码和所有实体类 一切都很好,但我正试图抽象一些冗余代码,我在尝试这样做时遇到了一些问题 基本上,我的所有实体在我的上下文类中都属于C# 通用表<;张力>;,c#,generics,linq-to-sql,entity,C#,Generics,Linq To Sql,Entity,尝试将LINQtoSQL用于我正在家里进行的一个小项目。我已经使用dbmetal.exe(来自DBLinq项目)针对本地MySQL数据库生成了一个上下文代码和所有实体类 一切都很好,但我正试图抽象一些冗余代码,我在尝试这样做时遇到了一些问题 基本上,我的所有实体在我的上下文类中都属于Table类型。例如,我有表格和表格 当我为存储库行为设计各种接口时,我意识到有些方法对于每个实体都是非常冗余的。例如,ID字段: User findById(int id); Calendar findById(i
Table
类型。例如,我有表格
和表格
当我为存储库行为设计各种接口时,我意识到有些方法对于每个实体都是非常冗余的。例如,ID字段:
User findById(int id);
Calendar findById(int id);
我设计了我的表,使它们都有3个共同的字段[ID、DATECREATED、DateUpdate]。因为这些字段是公共的,所以我希望有一个公共的行为,而不是为每个实体重写这些方法
因此,我让我的存储库类(UserRepository、CalendarRepository)继承一个公共的“存储库”类,其定义如下:
public class Repository<T> : IDisposable, IRepository<T> where T : class
{
protected MyContext context;
private DbLinq.Data.Linq.Table<T> currentTable;
protected Repository() {
context = new MyContext();
Type currentType = this.GetType().GetGenericArguments()[0];
currentTable = //Set currentTable based on currentType. e.g.: currentTable = context.User;
}
#region IRepository<T> Members
public T findById(int? id)
{
return currentTable.SingleOrDefault(d => d.ID == id);
}
public T findByDateCreated(DateTime dateCreated)
{
return currentTable.SingleOrDefault(d => DateTime.Equals(dateCreated, d.DateCreated));
}
public T findByDateUpdated(DateTime dateUpdated)
{
return currentTable.SingleOrDefault(d => DateTime.Equals(dateUpdated, d.DateUpdated));
}
public T insert(T domainObject)
{
currentTable.InsertOnSubmit(domainObject);
return domainObject;
}
public T save(T domainObject)
{
context.SubmitChanges();
return domainObject;
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (context != null)
context.Dispose();
}
#endregion
}
公共类存储库:IDisposable,IRepository其中T:class
{
受保护的MyContext上下文;
私有DbLinq.Data.Linq.Table currentTable;
受保护的存储库(){
context=newmycontext();
类型currentType=this.GetType().GetGenericArguments()[0];
currentTable=//根据currentType设置currentTable,例如:currentTable=context.User;
}
#地区成员
公共T findById(int?id)
{
返回currentTable.SingleOrDefault(d=>d.ID==ID);
}
公共T findByDateCreated(DateTime dateCreated)
{
返回currentTable.SingleOrDefault(d=>DateTime.Equals(dateCreated,d.dateCreated));
}
公共T findByDateUpdated(日期时间日期更新)
{
返回currentTable.SingleOrDefault(d=>DateTime.Equals(dateUpdated,d.dateUpdated));
}
公共T插入(T域对象)
{
currentTable.InsertOnSubmit(域对象);
返回域对象;
}
公共T保存(T域对象)
{
context.SubmitChanges();
返回域对象;
}
#端区
#区域IDisposable成员
公共空间处置()
{
if(上下文!=null)
context.Dispose();
}
#端区
}
事实证明这比我想象的要难。当我尝试设置:
currentTable = (Table<T>)context.User;
currentTable=(Table)context.User;
我得到以下错误:
Cannot convert type 'DbLinq.Data.Linq.Table<Models.Domain.User>' to 'DbLinq.Data.Linq.Table<T>'
无法将类型“DbLinq.Data.Linq.Table”转换为“DbLinq.Data.Linq.Table”
隐式转换也不起作用
有人成功地做过类似的事情吗?如果我必须让我所有的存储库类都使用完全相同的代码实现相同的findById方法,那将是非常悲哀的。。。我确信有一种方法可以避免这种情况,我就是找不到。:)
如果我不得不这么做的话,那就太可悲了
我的所有存储库类都实现
相同的findById方法具有
里面有相同的代码
代码不完全相同。在每种情况下,您都在上下文中引用不同的表
我理解你的逻辑;你想要干燥。但是,您拥有存储库的原因是通过注入模拟存储库而不是真实存储库来简化单元测试,从而使您能够抽象出数据访问逻辑。实现这一点的最实际(也是最灵活)的方法是保持表(和DAL对象)的独立性。通过尝试泛化DAL对象的一部分,您引入了额外的耦合,这将使单元测试复杂化 它是在编译时失败还是在运行时失败?的确,引用的对象不同,但代码相同。但我确实有单元测试的观点。。。IOC实际上是我使用Ninject的下一步。谢谢你的帮助,罗伯特。@罗伯特,即使我有5个方法完全相同的表,单元测试仍然那么重要吗?如果我想牺牲单元测试来获得更多的干燥度,我该怎么做呢?三天前,我和Lancelot遇到了同样的问题,但仍然无法创建一个通用结构来接受我的所有日志表。@AdrianoRR:澄清一下,存储库的目的是抽象出数据持久性。这样做可以促进单元测试,或者可以使用不同的供应商替换底层数据存储。实际上,单元测试只是用来确认存储库方法返回了正确的记录,而交换数据存储几乎从未发生过。@Robert我明白了。好吧,我愿意放弃这个案例的单元测试。到目前为止,我一直在修改我的db.dbml,这样它就可以支持我的DRYness(实际上是一个超级类)。然而,操纵dbml本身似乎不是一个好的做法,这就是为什么当我看到这篇文章时我非常兴奋,但是没有人问Lacelot的问题,只是你的澄清。@AdrianoRR:Lancelot的方法无论如何都是反模式的。在某些情况下,您必须为正在检索的内容命名,因此您最好在存储库方法中命名它,即
公共客户GetCustomer(int-id)
。试图通过传递类型参数在单个方法中实现这一点只会将复杂性推到其他地方。