Entity framework 将库从ObjectContext转换为DbContext
我有一个库(),它允许我使用实体框架非常轻松地围绕数据访问包装一个外观。它使用ObjectContext,并且就我的目的而言,它的性能已经足够好了 但是现在,我们正在兴奋地首先使用DbContext研究代码,当然,我们希望尽可能多地重用/调整我们现有的工作 使用IObjectContextAdapter转换Facade启用库时一切正常,直到我们尝试使用Facade时,收到以下错误: 类型“Employee”不能用作泛型类型或方法“DbContextManagement.FacadeBase”中的类型参数“tenty”。没有从“Employee”到“System.Data.Objects.DataClasses.EntityObject”的隐式引用转换 MSDN说: DbContext API不支持EntityObject派生类型,若要使用这些实体类型,必须使用ObjectContext API 这很好,但我如何才能继续完成重构以绕过这一缺陷呢 下面是一些代码(引入了换行符): FacadeBase.csEntity framework 将库从ObjectContext转换为DbContext,entity-framework,entity-framework-4.1,objectcontext,dbcontext,Entity Framework,Entity Framework 4.1,Objectcontext,Dbcontext,我有一个库(),它允许我使用实体框架非常轻松地围绕数据访问包装一个外观。它使用ObjectContext,并且就我的目的而言,它的性能已经足够好了 但是现在,我们正在兴奋地首先使用DbContext研究代码,当然,我们希望尽可能多地重用/调整我们现有的工作 使用IObjectContextAdapter转换Facade启用库时一切正常,直到我们尝试使用Facade时,收到以下错误: 类型“Employee”不能用作泛型类型或方法“DbContextManagement.FacadeBase”中的
namespace DbContextManagement
{
using System;
using System.Collections;
using System.Configuration;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Metadata.Edm;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Reflection;
public abstract class FacadeBase<TDbContext, TEntity>
where TDbContext : DbContext, new()
where TEntity : EntityObject
{
protected TDbContext DbContext
{
get
{
if (DbContextManager == null)
{
this.InstantiateDbContextManager();
}
return DbContextManager.GetDbContext<TDbContext>();
}
}
private DbContextManager DbContextManager { get; set; }
public virtual void Add(TEntity newObject)
{
var context = ((IObjectContextAdapter)this.DbContext).ObjectContext;
string entitySetName;
if (newObject.EntityKey != null)
{
entitySetName = newObject.EntityKey.EntitySetName;
}
else
{
string entityTypeName = newObject.GetType().Name;
var container = context.MetadataWorkspace.GetEntityContainer(
context.DefaultContainerName,
DataSpace.CSpace);
entitySetName = (from meta in container.BaseEntitySets
where meta.ElementType.Name ==
entityTypeName
select meta.Name).First();
}
context.AddObject(entitySetName, newObject);
}
public virtual void Delete(TEntity obsoleteObject)
{
var context = ((IObjectContextAdapter)this.DbContext).ObjectContext;
context.DeleteObject(obsoleteObject);
}
private void InstantiateDbContextManager()
{
var objectContextManagerConfiguration =
ConfigurationManager.GetSection("DbContext") as Hashtable;
if (objectContextManagerConfiguration != null &&
objectContextManagerConfiguration.ContainsKey("managerType"))
{
var managerTypeName =
objectContextManagerConfiguration["managerType"] as string;
if (string.IsNullOrEmpty(managerTypeName))
{
throw new ConfigurationErrorsException(
"The managerType attribute is empty.");
}
managerTypeName = managerTypeName.Trim().ToLower();
try
{
var frameworkAssembly =
Assembly.GetAssembly(typeof(DbContextManager));
var managerType =
frameworkAssembly.GetType(managerTypeName, true, true);
this.DbContextManager =
Activator.CreateInstance(managerType) as DbContextManager;
}
catch (Exception e)
{
throw new ConfigurationErrorsException(
"The managerType specified in the
configuration is not valid.", e);
}
}
else
{
throw new ConfigurationErrorsException(
"A Facade.DbContext tag or its managerType attribute
is missing in the configuration.");
}
}
}
}
namespace Facade
{
using System.Collections.Generic;
using System.Linq;
using DataModel;
using DataModel.Entities;
using DbContextManagement;
public sealed class EmployeeFacade : FacadeBase<FleetContext, Employee>
{
public Employee GetById(int? employeeId)
{
return employeeId == null
? null
: this.DbContext.Employees.FirstOrDefault(m => m.Id == employeeId);
}
}
}
namespace DataModel.Entities
{
public class Employee
{
public int Id { get; set; }
public string Surname { get; set; }
public string Forename { get; set; }
public string EmployeeNumber { get; set; }
}
}
如果您的实体是从
EntityObject
派生的,并且您要重用的代码依赖于基于EntityObject
的实体,则它是一个显示阻止器。在实体为POCO(无EntityObject
parent)之前,不能使用DbContext API
顺便说一句,您可以对ObjectContext
(和POCOs)使用仅代码映射,而不必使用DbContext
。你只需要:
- 为描述映射的每个POCO实体/复杂类型创建基于
或EntityTypeConfiguration
的类ComplexTypeConfiguration
- 使用
收集配置并调用DbModelBuilder
获取Build
实例DbModel
- 在
实例上调用DbModel
,以获取compiled
DbCompiledModel
- 应用程序生命周期的缓存编译模型
- 在编译模型上需要新的
实例调用ObjectContext
时CreateObjectContext
请注意,代码映射的功能集非常有限,因此,并非所有您当前在EDMX中拥有的功能都可以通过代码映射来实现。在上面给出的链接中,我非常感谢原始代码的作者,以下是我的结论。它通过了基本场景,但我还没有尝试过更深入的导航和相关查询。即使有问题,我认为这将是错误修复,而不是显示停止 来吧。下面的代码是可重用的,可用于多个上下文,这意味着您可以转到数据库,并在客户端的两行实际代码中返回一些内容 数据模型(类库项目) 您的EF代码是第一个使用DbContext POCO的项目,等等 DbContextManagement(类库项目) DbContextManager.cs
namespace DbContextManagement
{
using System.Data.Entity;
/// <summary>
/// Abstract base class for all other DbContextManager classes.
/// </summary>
public abstract class DbContextManager
{
/// <summary>
/// Returns a reference to an DbContext instance.
/// </summary>
/// <typeparam name="TDbContext">The type of the db context.</typeparam>
/// <returns>The current DbContext</returns>
public abstract TDbContext GetDbContext<TDbContext>()
where TDbContext : DbContext, new();
}
}
namespace DbContextManagement
{
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
/// <summary>
/// Manages multiple db contexts.
/// </summary>
public sealed class ScopedDbContextManager : DbContextManager
{
/// <summary>
/// List of Object Contexts.
/// </summary>
private List<DbContext> contextList;
/// <summary>
/// Returns the DbContext instance that belongs to the current DbContextScope.
/// If currently no DbContextScope exists, a local instance of an DbContext
/// class is returned.
/// </summary>
/// <typeparam name="TDbContext">The type of the db context.</typeparam>
/// <returns>Current scoped DbContext.</returns>
public override TDbContext GetDbContext<TDbContext>()
{
var currentDbContext = DbContextScope.GetCurrentDbContext<TDbContext>();
if (currentDbContext != null)
{
return currentDbContext;
}
if (this.contextList == null)
{
this.contextList = new List<DbContext>();
}
currentDbContext = this.contextList.OfType<TDbContext>().FirstOrDefault();
if (currentDbContext == null)
{
currentDbContext = new TDbContext();
this.contextList.Add(currentDbContext);
}
return currentDbContext;
}
}
}
namespace DbContextManagement
{
使用System.Data.Entity;
///
///所有其他DbContextManager类的抽象基类。
///
公共抽象类DbContextManager
{
///
///返回对DbContext实例的引用。
///
///数据库上下文的类型。
///当前DbContext
公共摘要TDbContext GetDbContext()
其中TDbContext:DbContext,new();
}
}
DbContextScope.cs
namespace DbContextManagement
{
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Threading;
/// <summary>
/// Defines a scope wherein only one DbContext instance is created, and shared by all of those who use it.
/// </summary>
/// <remarks>Instances of this class are supposed to be used in a using() statement.</remarks>
public class DbContextScope : IDisposable
{
/// <summary>
/// List of current DbContexts (supports multiple contexts).
/// </summary>
private readonly List<DbContext> contextList;
/// <summary>
/// DbContext scope definitiion.
/// </summary>
[ThreadStatic]
private static DbContextScope currentScope;
/// <summary>
/// Holds a value indicating whether the context is disposed or not.
/// </summary>
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="DbContextScope"/> class.
/// </summary>
/// <param name="saveAllChangesAtEndOfScope">if set to <c>true</c> [save all changes at end of scope].</param>
protected DbContextScope(bool saveAllChangesAtEndOfScope)
{
if (currentScope != null && !currentScope.isDisposed)
{
throw new InvalidOperationException("DbContextScope instances cannot be nested.");
}
this.SaveAllChangesAtEndOfScope = saveAllChangesAtEndOfScope;
this.contextList = new List<DbContext>();
this.isDisposed = false;
Thread.BeginThreadAffinity();
currentScope = this;
}
/// <summary>
/// Gets or sets a value indicating whether to automatically save all object changes at end of the scope.
/// </summary>
/// <value><c>true</c> if [save all changes at end of scope]; otherwise, <c>false</c>.</value>
private bool SaveAllChangesAtEndOfScope { get; set; }
/// <summary>
/// Save all object changes to the underlying datastore.
/// </summary>
public void SaveAllChanges()
{
var transactions = new List<DbTransaction>();
foreach (var context in this.contextList
.Select(dbcontext => ((IObjectContextAdapter)dbcontext)
.ObjectContext))
{
context.Connection.Open();
var databaseTransaction = context.Connection.BeginTransaction();
transactions.Add(databaseTransaction);
try
{
context.SaveChanges();
}
catch
{
/* Rollback & dispose all transactions: */
foreach (var transaction in transactions)
{
try
{
transaction.Rollback();
}
catch
{
// "Empty general catch clause suppresses any errors."
// Haven't quite figured out what to do here yet.
}
finally
{
databaseTransaction.Dispose();
}
}
transactions.Clear();
throw;
}
}
try
{
/* Commit all complete transactions: */
foreach (var completeTransaction in transactions)
{
completeTransaction.Commit();
}
}
finally
{
/* Dispose all transactions: */
foreach (var transaction in transactions)
{
transaction.Dispose();
}
transactions.Clear();
/* Close all open connections: */
foreach (var context in this.contextList
.Select(dbcontext => ((IObjectContextAdapter)dbcontext).ObjectContext)
.Where(context => context.Connection.State != System.Data.ConnectionState.Closed))
{
context.Connection.Close();
}
}
}
/// <summary>
/// Disposes the DbContext.
/// </summary>
public void Dispose()
{
// Monitor for possible future bugfix.
// CA1063 : Microsoft.Design : Provide an overridable implementation of Dispose(bool)
// on 'DbContextScope' or mark the type as sealed. A call to Dispose(false) should
// only clean up native resources. A call to Dispose(true) should clean up both managed
// and native resources.
if (this.isDisposed)
{
return;
}
// Monitor for possible future bugfix.
// CA1063 : Microsoft.Design : Modify 'DbContextScope.Dispose()' so that it calls
// Dispose(true), then calls GC.SuppressFinalize on the current object instance
// ('this' or 'Me' in Visual Basic), and then returns.
currentScope = null;
Thread.EndThreadAffinity();
try
{
if (this.SaveAllChangesAtEndOfScope && this.contextList.Count > 0)
{
this.SaveAllChanges();
}
}
finally
{
foreach (var context in this.contextList)
{
try
{
context.Dispose();
}
catch (ObjectDisposedException)
{
// Monitor for possible future bugfix.
// CA2202 : Microsoft.Usage : Object 'databaseTransaction' can be disposed
// more than once in method 'DbContextScope.SaveAllChanges()'.
// To avoid generating a System.ObjectDisposedException you should not call
// Dispose more than one time on an object.
}
}
this.isDisposed = true;
}
}
/// <summary>
/// Returns a reference to a DbContext of a specific type that is - or will be -
/// created for the current scope. If no scope currently exists, null is returned.
/// </summary>
/// <typeparam name="TDbContext">The type of the db context.</typeparam>
/// <returns>The current DbContext</returns>
protected internal static TDbContext GetCurrentDbContext<TDbContext>()
where TDbContext : DbContext, new()
{
if (currentScope == null)
{
return null;
}
var contextOfType = currentScope.contextList
.OfType<TDbContext>()
.FirstOrDefault();
if (contextOfType == null)
{
contextOfType = new TDbContext();
currentScope.contextList.Add(contextOfType);
}
return contextOfType;
}
}
}
namespace DbContextManagement
{
使用制度;
使用System.Collections.Generic;
使用System.Data.Common;
使用System.Data.Entity;
使用System.Data.Entity.Infrastructure;
使用System.Linq;
使用系统线程;
///
///定义一个范围,其中仅创建一个DbContext实例,并由所有使用它的人共享。
///
///此类的实例应该在using()语句中使用。
公共类DbContextScope:IDisposable
{
///
///当前数据库上下文列表(支持多个上下文)。
///
私有只读列表contextList;
///
///DbContext范围定义。
///
[线程静态]
私有静态DbContextScope currentScope;
///
///保存一个值,该值指示是否释放上下文。
///
私人住宅被出售;
///
///初始化类的新实例。
///
///如果设置为true[在范围结束时保存所有更改]。
受保护的DbContextScope(bool saveAllChangesAtEndOfScope)
{
if(currentScope!=null&&!currentScope.isDisposed)
{
抛出新的InvalidOperationException(“无法嵌套DbContextScope实例”);
}
this.SaveAllChangesAtEndOfScope=SaveAllChangesAtEndOfScope;
this.contextList=新列表();
this.isDisposed=false;
Thread.BeginThreadAffinity();
currentScope=这个;
}
///
///获取或设置一个值,该值指示是否在作用域末尾自动保存所有对象更改。
///
///如果[在范围末尾保存所有更改],则为true;否则为false。
私有bool SaveAllChangesAtEndOfScope{get;set;}
///
///将所有对象更改保存到基础数据存储。
///
public void SaveAllChanges()
{
var事务=新列表();
foreach(此.contextList中的变量上下文
.选择(dbcontext=>((IObjectContextAdapter)dbcontext)
.ObjectContext)
{
context.Connection.Open();
var databaseTransaction=context.Connection.BeginTransaction();
事务。添加(数据库事务);
尝试
{
续
namespace DbContextManagement
{
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
/// <summary>
/// Manages multiple db contexts.
/// </summary>
public sealed class ScopedDbContextManager : DbContextManager
{
/// <summary>
/// List of Object Contexts.
/// </summary>
private List<DbContext> contextList;
/// <summary>
/// Returns the DbContext instance that belongs to the current DbContextScope.
/// If currently no DbContextScope exists, a local instance of an DbContext
/// class is returned.
/// </summary>
/// <typeparam name="TDbContext">The type of the db context.</typeparam>
/// <returns>Current scoped DbContext.</returns>
public override TDbContext GetDbContext<TDbContext>()
{
var currentDbContext = DbContextScope.GetCurrentDbContext<TDbContext>();
if (currentDbContext != null)
{
return currentDbContext;
}
if (this.contextList == null)
{
this.contextList = new List<DbContext>();
}
currentDbContext = this.contextList.OfType<TDbContext>().FirstOrDefault();
if (currentDbContext == null)
{
currentDbContext = new TDbContext();
this.contextList.Add(currentDbContext);
}
return currentDbContext;
}
}
}
namespace DbContextManagement
{
/// <summary>
/// Defines a scope for a business transaction. At the end of the scope all object changes can be persisted to the underlying datastore.
/// </summary>
/// <remarks>Instances of this class are supposed to be used in a using() statement.</remarks>
public sealed class UnitOfWorkScope : DbContextScope
{
/// <summary>
/// Initializes a new instance of the <see cref="UnitOfWorkScope"/> class.
/// </summary>
/// <param name="saveAllChangesAtEndOfScope">if set to <c>true</c> [save all changes at end of scope].</param>
public UnitOfWorkScope(bool saveAllChangesAtEndOfScope)
: base(saveAllChangesAtEndOfScope)
{
}
}
}
namespace Facade
{
using System.Collections.Generic;
using System.Linq;
using DataModel;
using DataModel.Entities;
using DbContextManagement;
public class YourEntityFacade : FacadeBase<YourDbContext, YourEntity, int>
{
public override IEnumerable<YourEntity> GetAll()
{
return base.GetAll()
.Distinct()
.ToList();
}
}
}
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="DbContext" type="System.Configuration.SingleTagSectionHandler" />
</configSections>
<DbContext managerType="DbContextManagement.ScopedDbContextManager" />
<connectionStrings>
<add
name="YourDbContext"
providerName="System.Data.SqlClient"
connectionString="Your connection string" />
</connectionStrings>
</configuration>
namespace TestConsole
{
using System;
using System.Collections.Generic;
using DataModel.Entities;
using DbContextManagement;
using Facade;
public static class Program
{
public static void Main()
{
TestGetAll();
Console.ReadLine();
}
private static void TestGetAll()
{
Console.WriteLine();
Console.WriteLine("Test GetAll()");
Console.WriteLine();
IEnumerable<YourEntity> yourEntities;
using (new UnitOfWorkScope(false))
{
yourEntities= new YourEntityFacade().GetAll();
}
if (yourEntities != null)
{
foreach (var yourEntity in yourEntities)
{
Console.WriteLine(
string.Format("{0}, {1}",
yourEntity.Id,
yourEntity.Name));
}
}
else
{
Console.WriteLine("GetAll() NULL");
}
}
}
}