Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 针对接口编程&;实体框架4.0_C#_.net_Entity Framework_Interface_Entity Framework 4 - Fatal编程技术网

C# 针对接口编程&;实体框架4.0

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

我试图弄清楚,在使用实体框架4.0时,是否有可能坚持“针对接口而不是实现的程序”这一口号

虽然我发现了一个页面,解释了如何在使用linqtosql()时遵守上述规则,但我非常想知道是否有可能使用实体框架(也使用Linq)做到这一点

通常是这样使用的:

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>();
    }