解决了一个棘手的EF框架引入问题,所以做下记录。
最近在集成EF到现有系统中,由于现有系统比较旧,调用ToList的时候就会报这个错误
错误代码
var file = _ctx.FileInfo.FirstOrDefault(t => t.ID == uid);
报错信息
Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.
无法将类型为“Glimpse.Ado.AlternateType.GlimpseDbConnection”的对象强制转换为类型“System.Data.SqlClient.SqlConnection”。
堆栈1
System.NotSupportedException: Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.
在 System.Data.Entity.Utilities.DbProviderFactoryExtensions.GetProviderInvariantName(DbProviderFactory factory)
在 System.Data.Entity.Infrastructure.DependencyResolution.DefaultInvariantNameResolver.GetService(Type type, Object key)
在 System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
在 System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
在 System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
在 System.Data.Entity.Infrastructure.DependencyResolution.RootDependencyResolver.GetService(Type type, Object key)
在 System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
在 System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
在 System.Data.Entity.Infrastructure.DependencyResolution.CompositeResolver`2.GetService(Type type, Object key)
在 System.Data.Entity.Infrastructure.DependencyResolution.DbDependencyResolverExtensions.GetService[T](IDbDependencyResolver resolver, Object key)
在 System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInvariantName(DbConnection connection)
在 System.Data.Entity.Internal.InternalConnection.get_ProviderName()
在 System.Data.Entity.Internal.DefaultModelCacheKeyFactory.Create(DbContext context)
在 System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
在 System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
在 System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
在 System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
在 System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
在 System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
在 UFSoft.UBF.MVC.MainController.TestEF(String uid)
堆栈2
System.InvalidCastException: 无法将类型为“Glimpse.Ado.AlternateType.GlimpseDbConnection”的对象强制转换为类型“System.Data.SqlClient.SqlConnection”。
在 System.Data.SqlClient.SqlCommand.set_DbConnection(DbConnection value)
在 System.Data.Entity.Core.Common.Utils.CommandHelper.SetStoreProviderCommandState(EntityCommand entityCommand, EntityTransaction entityTransaction, DbCommand storeProviderCommand)
在 System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.PrepareEntityCommandBeforeExecution(EntityCommand entityCommand)
在 System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
在 System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
在 System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
在 System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClassb.b__9()
在 System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
在 System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
在 System.Data.Entity.Core.Objects.ObjectQuery`1..GetEnumerator>b__0()
在 System.Lazy`1.CreateValue()
在 System.Lazy`1.LazyInitValue()
在 System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
在 System.Linq.Enumerable.Single[TSource](IEnumerable`1 source)
在 System.Data.Entity.Migrations.History.HistoryRepository.QueryExists(String contextKey)
在 System.Data.Entity.Migrations.History.HistoryRepository.Exists(String contextKey)
在 System.Data.Entity.Migrations.History.HistoryRepository.GetLastModel(String& migrationId, String contextKey)
在 System.Data.Entity.Migrations.History.HistoryRepository.GetLastModel()
在 System.Data.Entity.Internal.ModelCompatibilityChecker.CompatibleWithModel(InternalContext internalContext, ModelHashCalculator modelHashCalculator, Boolean throwIfNoMetadata)
在 System.Data.Entity.CreateDatabaseIfNotExists`1.InitializeDatabase(TContext context)
在 System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
在 System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
在 System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
在 System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)
在 System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
在 System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
在 System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
在 System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
在 System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
在 UFSoft.UBF.MVC.MainController.TestEF(String uid)
位置 G:yonyouU9CEUBFUBFADFUIUI_MVCControllerMainController.cs:行号 3402
首先看了下第一个报错
应该是配置问题导致的,所以新建了一个EF项目,看到默认的配置文件,进行对比。
<?xml version="1.0" encoding="utf-8"?> <!-- For more information on how to configure your ASP.NET application, please visit https://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> </system.web> <system.codedom> <compilers> <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" /> <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE="Web" /optionInfer+" /> </compilers> </system.codedom> <entityFramework> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> </providers> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v13.0" /> </parameters> </defaultConnectionFactory> </entityFramework> <connectionStrings> <add name="Model1" connectionString="data source=lijianhua;initial catalog=U9CE20210418Doc;persist security info=True;user id=sa;password=******;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration>
看到了连接字符串后面带一个 providerName 参数,但是我的项目里连接字符串是动态配置的,没法写到配置文件里,只能通过代码实现传入 providerName
所以创建 DbConnection 的时候是直接 new 出来的,所以EF并不能识别这个类型。
用下面的工厂模式方式创建即可
public static DbConnection GetConn(string connstr) { var connection = DbProviderFactories.GetFactory("System.Data.SqlClient").CreateConnection(); connection.ConnectionString = connstr; //配置了 U9_Glimpse_Allowed 才会返回此类型 //if (UFIDA.U9.UI.PDHelper.FormAuthorityHelper.IsUserInRole("Glimpse", long.Parse(CSContext.Current.OrgId), long.Parse(CSContext.Current.UserID))) if (connection is GlimpseDbConnection) { return ((GlimpseDbConnection)connection).InnerConnection as SqlConnection; } return connection; }
但是创建完之后,发现了第二个报错。
创建出来的类型并不是我需要的 DbConnection 类型,是得到的 GlimpseDbConnection 类型,这是由于目前的老框架在这块进行了区分,这个GlimpseDbConnection 是为了分析性能而特别创建的 Connection 。但是EF并不能接收这个类型。
所以采用后面的转换方式进行转换即可正常使用。
参考文档1
http://aiuxian.com/article/p-tewsmagq-btb.html
参考文档2
至此已经可以正常在项目里使用EF框架,进行愉快的增删改查了。
EF集成工作圆满结束!!!