但是,我有一个关于如何为我的应用程序所包含的对象设计实体基类的问题.我有一个简单的类库,Web应用程序是建立在它之上的.这个库暴露了一个IRepository接口,默认实现(该应用程序使用一个)使用LINQ到sql盖下(在DataContext等不会暴露到Web应用程序),并只包含的方式来获取这些实体.存储库基本上看起来像这样(简化):
public interface IRepository { IEnumerable<T> FindAll<T>() where T : Entity T Get<T>(int id) where T : Entity }
默认实现使用DataContext上的GetTable()方法来提供正确的数据.
但是,这要求基类“Entity”具有一些功能.通过创建一个与Linq-to-sql给我的映射对象同名的部分类,很容易让我的对象继承它,但是这样做的“正确”方法是什么?
例如,上面的接口具有通过它的id获取实体的功能 – 从实体派生的所有不同类的类确实具有int类型的“id”字段(从它们各自的表的主键映射),但是我如何以一种允许我像这样实现IRepository的方式来指定它呢?
public class ConcreteRepository : IRepository { private SomeDataContext db = new SomeDataContext(); public IEnumerable<T> FindAll<T>() where T : Entity { return db.GetTable<T>().ToList(); } public T Get(int id) where T : Entity { return db.GetTable<T>().Where(ent => ent.id == id).FirstOrDefault(); } }
我在无编译器的PC上从内存中执行此操作,因此原谅任何错误,您希望得到我的意图.
这里的诀窍当然是为了编译它,必须确定Entity承诺从它派生的每个人都有一个id字段.
我可以创建一个抽象字段,或者由Linq-to-sql粘贴在生成的类中的id字段“隐藏”的普通字段.
但这一切都像是作弊,甚至给编译器警告.
应该“实体”真的是“IEntity”(而不是接口),我应该尝试以Linq-to-sql将实现的方式定义id字段?这也可以很容易地指定实体实现者需要实现的其他接口.
或者“实体”应该是一个带有抽象id字段的抽象基类,它是否应该以抽象方式实现所需的接口以供其他人覆盖?
我不太清楚C#是否能够找到优雅的解决方案,所以我很乐意听到更有经验的系统设计师的一些基础经验.
谢谢!
编辑4月10日:
我看到我在这里遗漏了一些重要的东西.我的IRepository有两个具体的实现 – 一个是使用LINQ to sql的“真实”实现,另一个是现在只使用List的InMemoryRepository,用于单元测试等.
添加的两个解决方案都适用于其中一种情况,而不适用于另一种情况.因此,如果可能的话,我需要一种方法来定义从Entity继承的所有内容都将具有“id”属性,并且这将与LINQ to sql DataContext一起使用而不会“作弊”.
解决方法
public int Id {}
然后创建一个接口
public interface IIdentifiable { Id { get; } }
然后是最乏味的部分:(,为所有实体创建一个部分类,并使其实现IIdentifiable.
然后,存储库类可以如下所示:
public class Repository<T> : IRepository where T : IIdentifiable { }
以下代码将起作用:
db.GetTable<T>().SingleOrDefault(ent => ent.Id.Equals(id));
如果你不使用生成的类并自己制作,从这个角度来看甚至更简单.
编辑:
而不是ent => ent.Id == id使用ent => ent.Id.Equals(ID).刚刚测试过,以下是一个完整的工作示例:
public interface IIdentifiable { int Id { get; } } public class Repository<T> where T : class,IIdentifiable { TestDataContext dataContext = new TestDataContext(); public T GetById(int id) { T t = dataContext.GetTable<T>().SingleOrDefault(elem => elem.Id.Equals(id)); return t; } } public partial class Item : IIdentifiable { } class Program { static void Main(string[] args) { Repository<Item> itemRepository = new Repository<Item>(); Item item = itemRepository.GetById(1); Console.WriteLine(item.Text); } }