C# 针对接口编程&;实体框架4.0
我试图弄清楚,在使用实体框架4.0时,是否有可能坚持“针对接口而不是实现的程序”这一口号 虽然我发现了一个页面,解释了如何在使用linqtosql()时遵守上述规则,但我非常想知道是否有可能使用实体框架(也使用Linq)做到这一点 通常是这样使用的:C# 针对接口编程&;实体框架4.0,c#,.net,entity-framework,interface,entity-framework-4,C#,.net,Entity Framework,Interface,Entity Framework 4,我试图弄清楚,在使用实体框架4.0时,是否有可能坚持“针对接口而不是实现的程序”这一口号 虽然我发现了一个页面,解释了如何在使用linqtosql()时遵守上述规则,但我非常想知道是否有可能使用实体框架(也使用Linq)做到这一点 通常是这样使用的: var query = from pages in dataContext.Pages where pages.IsPublished select pages; foreach (Page page in query) { // do
var query = from pages in dataContext.Pages where pages.IsPublished select pages;
foreach (Page page in query)
{
// do something with page...
var routeQuery = from routes in page.Route where route.IsValid select routes;
foreach (Route route in routeQuery)
{
// do something with route
}
}
但我想这样使用它:
var query = from pages in dataContext.Pages where pages.IsPublished select pages;
foreach (IPage page in query)
{
// do something with page...
var routeQuery = from routes in page.Route where route.IsValid select routes;
foreach (IRoute route in routeQuery)
{
// do something with route
}
}
从本质上讲,我希望能够通过使用接口将实体框架的DataContext传递出程序集/子系统,并在其中实例化。数据上下文提供的所有信息都应该是接口的形式,而不是实际的类
我希望将实现实体的实际类保持在程序集内部,并且只公开它们实现的接口
实体框架是否可以实现这一点?如果没有,是否有其他O/R映射器可以以这种方式使用
如果这不是进一步将DB与实际应用程序分离的好方法,我很想听听您的建议。好的解决方案(在我看来),是执行以下操作:
为实体数据模型创建存储库,公开ICollection
或IQueryable
在存储库上使用界面:
public interface IRepository
{
public ICollection<Person> Find(string name); // tighter, more maintanability
public IQueryable<Person> Find(); // full power! but be careful when lazy loading
公共接口IRepository
{
public ICollection Find(字符串名);//更紧凑,更易于维护
public IQueryable Find();//满功率!但在延迟加载时要小心
由于接口的原因,您可以交换输入输出模拟,其他ORM:
public class MockRepo : IRepository
{
public List<Person> persons; // mimics entity set
}
公共类MockRepo:IRepository
{
公共列表人员;//模拟实体集
}
你能抽象的东西只有这么多
如果您担心使用ObjectSet(绑定到EF),请使用POCO
查看我的其他一些问题以获取更多信息(因为我们现在正在构建此体系结构)
另外,考虑使用依赖项注入。在这里,您可以让存储库摆脱管理ObjectContext的工作——您可以向存储库注入一个工作单元(它是ObjectContext的包装器——因此多个存储库或聚合根可以处理同一上下文)
在我们的解决方案中,除了存储库之外,没有任何内容涉及实体框架(或任何持久性逻辑),存储库位于单独的程序集中
HTH。您可以使需要接口的存储库覆盖具体对象,并使用EF生成的类的部分类实现这些接口。不过,我不确定这是否真的值得付出努力。您可以遵循您提到的L2S示例中的大部分逻辑来实现接口based EF Repository类。一个主要的区别是Repository方法。它有点不同,因为EF在从一个IQueryable转换到另一个IQueryable时不使用Cast。我使用反射来解决这个问题 以下是为EF Repository类重新编写的Repository方法的示例:
public IQueryable<T> Repository<T>()
where T : class
{
if (typeof(T).IsInterface)
{
// if T is an interface then get the actual EntityObject Type by calling GetEntityType
// so that entityType can be used to call back to this method
Type entityType = this.GetEntityType<T>();
MethodInfo mi = this.GetType().GetMethod("Repository");
// set the T in Repository<T> to be the entity type
Type[] genericTypes = new Type[] { entityType };
mi = mi.MakeGenericMethod(genericTypes);
// call Repository<T>
object result = mi.Invoke(this, new object[0]);
return result as IQueryable<T>;
}
else
{
return this._context.CreateQuery<T>(this.GetEntitySetName<T>());
}
}
private Type GetEntityType<T>()
{
if (this.TableMaps.ContainsKey(typeof(T)))
{
return this.TableMaps[typeof(T)];
}
else
{
return typeof(T);
}
}
publicIQueryable存储库()
T:在哪里上课
{
if(类型(T).IsInterface)
{
//如果T是接口,则通过调用GetEntityType获取实际的EntityObject类型
//因此entityType可用于回调此方法
类型entityType=this.GetEntityType();
MethodInfo mi=this.GetType().GetMethod(“存储库”);
//将存储库中的T设置为实体类型
类型[]genericTypes=新类型[]{entityType};
mi=mi.MakeGenericMethod(genericTypes);
//调用存储库
object result=mi.Invoke(这是新对象[0]);
返回可查询的结果;
}
其他的
{
返回此值。_context.CreateQuery(this.GetEntitySetName());
}
}
私有类型GetEntityType()
{
if(this.TableMaps.ContainsKey(typeof(T)))
{
返回此。TableMaps[类型(T)];
}
其他的
{
返回类型(T);
}
}
我用EF 5.0实现了这一点。解决方案太复杂,无法发布。我可以给出非常高的级别描述
存储库的基类看起来像
public class GenericRepository<TEntityInterface, TEntity>
where TDataInterface : TEntityInterface
where TEntity : class, IBaseEntityInterface, new()
公共类通用存储库
其中TDataInterface:TEntityInterface
其中tenty:class,IBaseEntityInterface,new()
此存储库的子类看起来像
public class EmployeeRepository<TEntity> : GenericRepository<IEmployeeEntity, TEntity>, IEmployeeRepository
where TEntity : class, IEmployeeEntity, new()
公共类EmployeeRepository:GenericRepository,IEEmployeeRepository
其中tenty:class,IEEmployeeEntity,new()
我使用自定义实体的生成来继承实体接口,或者您可以为每个EF实体创建分部类来继承接口。我使用代码生成脚本为与实体上的属性相关的实体生成接口。所有实体都继承IBASeeEntityInterface
在代码中的某个时刻(在我的例子中使用的是注入框架),您将EF实体与存储库结合起来,因此
Bind<IEmployeeRepository>().To<EmployeeRepository<EmployeeEntity>();
Bind().to感谢您的回答。是否可以让存储库返回接口的ICollection,例如使用EF时的ICollection?另一个问题:-):您向其余应用程序公开了多少存储库?是否有一些逻辑,例如IPersonProvider.GetPerson(字符串名)这是由应用程序调用的,最终隐藏了存储库,或者应用程序是否知道iRecository?@Timo Kosig-这两个问题都很好:)是的,我认为这是可能的-只要您返回ICollection而不是IQueryable。为此,您需要使用纯POCO(无代码生成)。我使用的。但缺点是,您需要让所有POCO实现一个接口,纯粹是为了帮助存储库。在我看来,这不是一个好主意。您应该抽象掉持久性,而不是您正在使用POCO的事实。POCO
public IList<TEntityInterface> Where(Expression<Func<TEntityInterface, bool>> predicate, params string[] includedProperties)
{
DbQuery<TEntity> query = Context.Set<TEntity>();
foreach (string prop in includedProperties)
query = query.Include(prop);
return query.Where(predicate).ToList<TEntityInterface>();
}