Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.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
Entity framework 如何使用依赖项注入处理资源_Entity Framework_Dependency Injection_Structuremap_Dispose - Fatal编程技术网

Entity framework 如何使用依赖项注入处理资源

Entity framework 如何使用依赖项注入处理资源,entity-framework,dependency-injection,structuremap,dispose,Entity Framework,Dependency Injection,Structuremap,Dispose,我正在使用StructureMap解析对存储库类的引用。My repository接口实现IDisposable,例如 public interface IMyRepository : IDisposable { SomeClass GetById(int id); } 使用实体框架实现接口: public MyRepository : IMyRepository { private MyDbContext _dbContext; public MyDbContext()

我正在使用StructureMap解析对存储库类的引用。My repository接口实现IDisposable,例如

public interface IMyRepository : IDisposable
{
  SomeClass GetById(int id);
}
使用实体框架实现接口:

public MyRepository : IMyRepository
{
    private MyDbContext _dbContext;

    public MyDbContext()
    {
        _dbContext = new MyDbContext();
    }

    public SomeClass GetById(int id)
    {
        var query = from x in _dbContext
                    where x.Id = id
                    select x;
        return x.FirstOrDefault();
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }
}
public class EntityFrameworkNorthwindUnitOfWorkFactory
    : INorthwindUnitOfWorkFactory
{
    public NorthwindUnitOfWork CreateNew()
    {
        var db = new ObjectContext("name=NorthwindEntities");
        db.DefaultContainerName = "NorthwindEntities";
        var mapper = new EntityFrameworkDataMapper(db);
        return new NorthwindUnitOfWork(mapper);
    }
}

无论如何,正如前面提到的,我正在使用StructureMap来解析IMyRepository。因此,我应该在何时、何地以及如何调用dispose方法?

您可以这样声明IMyRepository,而不是将dispose添加到IMyRepository中:

public interface IMyRepository: IDisposable
{
  SomeClass GetById(int id);
} 
public sealed class Client
{
    private readonly INorthwindUnitOfWorkFactory factory;

    public Client(INorthwindUnitOfWorkFactory factory)
    {
        this.factory = factory;
    }

    public void Do()
    {
        using (NorthwindUnitOfWork db = 
            this.factory.CreateNew())
        {
            // 'Customers' is a repository.
            var customer = db.Customers.GetById(1);

            customer.Name = ".NET Junkie";

            db.SubmitChanges();
        }
    }
}
这样,您可以确保所有存储库有时都会调用Dispose,并且可以在存储库对象上使用C#“using”模式:

using (IMyRepository rep = GetMyRepository(...))
{
   ... do some work with rep
}

如果你想把它做好,我建议你做一些改变:

1-存储库中没有数据上下文的私有实例。如果您使用多个存储库,那么最终将使用多个上下文

2-要解决上述问题,请将上下文包装在工作单元中。通过ctor将工作单元传递到存储库:
public MyRepository(IUnitOfWork uow)

3-使工作单元实现IDisposable。工作单元应该在请求开始时“重新设置”,因此应该在请求完成时进行处理。存储库不应该实现IDisposable,因为它不直接使用资源——它只是减轻了资源的负担。DataContext/工作单元应实现IDisTable


4-假设您使用的是web应用程序,您不需要显式调用dispose-我重复,您不需要显式调用dispose方法。StructureMap有一个名为
HttpContextBuildPolicy.DisposeAndClearAll()的方法。这样做的目的是对实现IDisposable的任何HTTP作用域对象调用“Dispose”方法。将此调用插入
应用程序\u EndRequest
(Global.asax)。另外,我相信有一个更新的方法,叫做RelaseAtHelpSistDebug对象或一些东西——记不起这个名字。

< P> <强>警告< /强>:请注意,我的观点已经改变,你应该考虑过时的建议。请阅读最后的更新


虽然DI框架可以为您管理对象的生命周期,有些甚至可以在您使用完对象后为您处置对象,但它使对象处置过于隐式。创建
IDisposable
接口是因为需要对资源进行确定性清理。因此,在DI的上下文中,我个人喜欢将此清理非常明确。当你把它明确化时,你基本上有两个选择:1。配置DI以返回瞬态对象,并自行处理这些对象。2.配置工厂并指示工厂创建新实例

与第一种方法相比,我更喜欢第二种方法,因为特别是在进行依赖项注入时,您的代码并不像它可能的那样干净。例如,查看以下代码:

public sealed class Client : IDisposable
{
    private readonly IDependency dependency;

    public Client(IDependency dependency)
    {
        this. dependency = dependency;
    }

    public void Do()
    {
        this.dependency.DoSomething();
    }

    public Dispose()
    {
        this.dependency.Dispose();
    }
}
虽然这段代码显式地处理依赖关系,但它可能会让读者感到惊讶,因为资源通常只应由资源的所有者来处理。显然,
客户端
在注入资源时成为了资源的所有者

因此,我赞成使用工厂。看看这个例子:

public sealed class Client
{
    private readonly IDependencyFactory factory;

    public Client(IDependencyFactory factory)
    {
        this.factory = factory;
    }

    public void Do()
    {
        using (var dependency = this.factory.CreateNew())
        {
            dependency.DoSomething();
        }
    }
}
此示例的行为与上一个示例完全相同,但请参见
客户机
类如何不再实现
IDisposable
,因为它在
Do
方法中创建和处理资源

注入工厂是实现这一点的最明确的方式(最不出人意料的途径)。这就是我喜欢这种风格的原因。这样做的缺点是您经常需要定义更多的类(用于工厂),但我个人并不介意


RPM1984要求提供更具体的示例

我不会让存储库实现
IDisposable
,而是让一个工作单元实现
IDisposable
,控制/包含存储库,并让一个工厂知道如何创建新的工作单元。考虑到这一点,上述代码将如下所示:

public interface IMyRepository: IDisposable
{
  SomeClass GetById(int id);
} 
public sealed class Client
{
    private readonly INorthwindUnitOfWorkFactory factory;

    public Client(INorthwindUnitOfWorkFactory factory)
    {
        this.factory = factory;
    }

    public void Do()
    {
        using (NorthwindUnitOfWork db = 
            this.factory.CreateNew())
        {
            // 'Customers' is a repository.
            var customer = db.Customers.GetById(1);

            customer.Name = ".NET Junkie";

            db.SubmitChanges();
        }
    }
}
在我使用并描述的设计中,我使用了一个具体的
NorthwindUnitOfWork
类,该类封装了一个
IDataMapper
,它是通向底层LINQ提供程序(如LINQ到SQL或实体框架)的网关。在sumary,设计如下:

  • 在客户机中注入一个
    INorthwindUnitOfWorkFactory
  • 该工厂的特定实现创建了一个具体的
    NorthwindUnitOfWork
    类,并向其中注入了一个特定于O/RM的
    IDataMapper
  • NorthwindUnitOfWork
    实际上是围绕
    IDataMapper
    的类型安全包装,而
    NorthwindUnitOfWork
    请求
    IDataMapper
    存储库,并将提交更改和处置的请求转发给映射程序
  • IDataMapper
    返回
    Repository
    类,存储库实现
    IQueryable
    以允许客户端在存储库上使用LINQ
  • IDataMapper
    的具体实现包含对O/RM特定工作单元的引用(例如EF的
    ObjectContext
    )。因此,
    IDataMapper
    必须实现
    IDisposable
  • 这将导致以下设计:

    public interface INorthwindUnitOfWorkFactory
    {
        NorthwindUnitOfWork CreateNew();
    }
    
    public interface IDataMapper : IDisposable
    {
        Repository<T> GetRepository<T>() where T : class;
    
        void Save();
    }
    
    public abstract class Repository<T> : IQueryable<T>
        where T : class
    {
        private readonly IQueryable<T> query;
    
        protected Repository(IQueryable<T> query)
        {
            this.query = query;
        }
    
        public abstract void InsertOnSubmit(T entity);
    
        public abstract void DeleteOnSubmit(T entity);
    
        // IQueryable<T> members omitted.
    }
    
    剩下的是在OrthwindUnitofWorkFactory中的
    的具体实现和
    IDataMapper
    的具体实现。以下是实体框架的一个示例:

    public MyRepository : IMyRepository
    {
        private MyDbContext _dbContext;
    
        public MyDbContext()
        {
            _dbContext = new MyDbContext();
        }
    
        public SomeClass GetById(int id)
        {
            var query = from x in _dbContext
                        where x.Id = id
                        select x;
            return x.FirstOrDefault();
        }
    
        public void Dispose()
        {
            _dbContext.Dispose();
        }
    }
    
    public class EntityFrameworkNorthwindUnitOfWorkFactory
        : INorthwindUnitOfWorkFactory
    {
        public NorthwindUnitOfWork CreateNew()
        {
            var db = new ObjectContext("name=NorthwindEntities");
            db.DefaultContainerName = "NorthwindEntities";
            var mapper = new EntityFrameworkDataMapper(db);
            return new NorthwindUnitOfWork(mapper);
        }
    }
    
    以及
    EntityFrameworkDataMapper

    public sealed class EntityFrameworkDataMapper : IDataMapper
    {
        private readonly ObjectContext context;
    
        public EntityFrameworkDataMapper(ObjectContext context)
        {
            this.context = context;
        }
    
        public void Save()
        {
            this.context.SaveChanges();
        }
    
        public void Dispose()
        {
            this.context.Dispose();
        }
    
        public Repository<T> GetRepository<T>() where T : class
        {
            string setName = this.GetEntitySetName<T>();
    
            var query = this.context.CreateQuery<T>(setName);
            return new EntityRepository<T>(query, setName);
        }
    
        private string GetEntitySetName<T>()
        {
            EntityContainer container =
                this.context.MetadataWorkspace.GetEntityContainer(
                this.context.DefaultContainerName, DataSpace.CSpace);
    
            return (
                from item in container.BaseEntitySets
                where item.ElementType.Name == typeof(T).Name
                select item.Name).First();
        }
    
        private sealed class EntityRepository<T>
            : Repository<T> where T : class
        {
            private readonly ObjectQuery<T> query;
            private readonly string entitySetName;
    
            public EntityRepository(ObjectQuery<T> query,
                string entitySetName) : base(query)
            {
                this.query = query;
                this.entitySetName = entitySetName;
            }
    
            public override void InsertOnSubmit(T entity)
            {
                this.query.Context.AddObject(entitySetName, entity);
            }
    
            public override void DeleteOnSubmit(T entity)
            {
                this.query.Context.DeleteObject(entity);
            }
        }
    }
    
    公共密封类EntityFrameworkDataMapper:IDataMapper
    {
    私有只读对象上下文;
    公共EntityFrameworkDataMapper(ObjectContext上下文)
    {
    this.context=上下文;
    }
    公共作废保存()
    {
    this.context.SaveChanges();
    }
    公共空间处置()
    {