欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

記一次EFCore類(lèi)型轉(zhuǎn)換錯(cuò)誤及解決方案

 更新時(shí)間:2021年03月05日 14:29:49   作者:Hello 尋夢(mèng)者!  
這篇文章主要介紹了記一次EFCore類(lèi)型轉(zhuǎn)換錯(cuò)誤及解決方案,幫助大家更好的理解和學(xué)習(xí)使用asp.net core,感興趣的朋友可以了解下

一  背景

  今天在使用EntityFrameworkCore 查詢的時(shí)候在調(diào)試的時(shí)候總是提示如下錯(cuò)誤:Unable to cast object of type 'System.Data.SqlTypes.SqlString' to type 'System.Data.SqlTypes.SqlGuid' 第一次看這個(gè)報(bào)錯(cuò)肯定是數(shù)據(jù)庫(kù)實(shí)體和EFCore中定義的某種類(lèi)型不匹配從而導(dǎo)致類(lèi)型轉(zhuǎn)換錯(cuò)誤,但是業(yè)務(wù)涉及到這么多的實(shí)體Entity,那么到底是哪里類(lèi)型無(wú)法匹配呢?所以第一步肯定是調(diào)試代碼,然后看報(bào)錯(cuò)信息,這里我們首先貼出完整的報(bào)錯(cuò)信息,從而方便自己分析具體問(wèn)題?!?/p>

System.InvalidCastException: Unable to cast object of type 'System.Data.SqlTypes.SqlString' to type 'System.Data.SqlTypes.SqlGuid'.
 at System.Data.SqlClient.SqlBuffer.get_SqlGuid()
 at System.Data.SqlClient.SqlDataReader.GetGuid(Int32 i)
 at lambda_method(Closure , DbDataReader )
 at Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader)
 at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer)
 at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
 at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
 at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
 at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
 at System.Linq.Lookup`2.CreateForJoin(IEnumerable`1 source, Func`2 keySelector, IEqualityComparer`1 comparer)
 at System.Linq.Enumerable.JoinIterator[TOuter,TInner,TKey,TResult](IEnumerable`1 outer, IEnumerable`1 inner, Func`2 outerKeySelector, Func`2 innerKeySelector, Func`3 resultSelector, IEqualityComparer`1 comparer)+MoveNext()
 at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
 at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
 at Sunlight.Dcs.Application.Sales.SalesOrder.DegradedVehicleContracts.DegradedVehicleContractService.QueryByIdAsync(Int32 id) in E:\63318\sales-service\src\sales.orders\Application.Sales.Orders\SalesOrder\DegradedVehicleContracts\DegradedVehicleContractService.cs:line 99
 at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task`1 actualReturnValue, Func`1 postAction, Action`1 finalAction)
 at Sunlight.Dcs.WebApi.Sales.Controllers.Orders.DegradedVehicleContractController.QueryById(Int32 id) in E:\63318\sales-service\src\WebApi.Sales\Controllers\Orders\DegradedVehicleContractController.cs:line 50
 at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
 at System.Threading.Tasks.ValueTask`1.get_Result()
 at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
 at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
 at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
 at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
 at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
 at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()

二  解決方案

  有了上面的報(bào)錯(cuò)信息我們就能夠知道大致方向,接下來(lái)我們首先來(lái)看看報(bào)錯(cuò)信息的這段代碼。

public async Task<SimpleDegradedVehicleContractOutput> QueryByIdAsync(int id) {
 var queryResult = await _degradedVehicleContractRepository.GetAll()
 .Include(d => d.DegradedVehicleContractDetails)
 .SingleOrDefaultAsync(mp => mp.Id == id);
 if (queryResult == null)
 throw new ValidationException($"當(dāng)前Id為:{id}的降級(jí)車(chē)合同沒(méi)有找到");
 var result = _objectMapper.Map<SimpleDegradedVehicleContractOutput>(queryResult);
 result.Details = _objectMapper.Map<List<DegradedVehicleContractDetailDto>>(queryResult.DegradedVehicleContractDetails);

 //獲取ProductId
 var productIds = queryResult.DegradedVehicleContractDetails.Select(d => d.ProductId).Distinct().ToArray();
 //車(chē)輛Id
 var vinLists = queryResult.DegradedVehicleContractDetails.Select(r => r.Vin).Distinct().ToArray();

 var detailResult = (from detail in queryResult.DegradedVehicleContractDetails
 join product in _productRepository.GetAll().Where(p => productIds.Contains(p.Id))
 on detail.ProductId equals product.Id
 join vehicleDict in _vehicleInformationRepository.GetAll().Where(v => vinLists.Contains(v.Vin))
 on detail.Vin equals vehicleDict.Vin
 select new {
 ProductId = product.Id,
 product.ProductType,
 VehicleId = vehicleDict.Id,
 detail.Vin
 }).ToDictionary(r => Tuple.Create(r.ProductId, r.Vin), r => new { r.ProductType, r.VehicleId });

 result.Details.ForEach(r => {
 r.ProductType = detailResult[Tuple.Create(r.ProductId, r.Vin)]?.ProductType;
 r.VehicleId = detailResult[Tuple.Create(r.ProductId, r.Vin)].VehicleId;
 });

 return result;
 }

  2.1 定位報(bào)錯(cuò)位置

  通過(guò)直接對(duì)代碼進(jìn)行調(diào)試,我們發(fā)現(xiàn)只要代碼執(zhí)行獲取detailResult這一步的時(shí)候就會(huì)出現(xiàn)上面的錯(cuò)誤,那么到這里我們就可以推斷錯(cuò)誤的地方就在這里了,所以后面我們的重點(diǎn)就是分析這段代碼。

  2.2 定位產(chǎn)生錯(cuò)誤的表名稱

  這里就是利用前面的Include方法來(lái)查詢到queryResult結(jié)果,然后利用queryResult.DegradedVehicleContractDetails來(lái)和Product以及VehicleInformation表來(lái)做inner join,這里你可能對(duì)_productRepository以及_vehicleInformationRepository這個(gè)局部變量不是十分熟悉,那么我們先來(lái)看看這個(gè)局部變量的定義以及初始化。

 private readonly IRepository<Product> _productRepository;
 private readonly IRepository<VehicleInformation> _vehicleInformationRepository;

   上面是局部變量的定義,在我們的示例代碼中我們使用ABP框架來(lái)作為整個(gè)項(xiàng)目代碼的基礎(chǔ)框架,這里的IRepository接口來(lái)自于ABP框架中定義的接口類(lèi)型用于直接操作數(shù)據(jù)庫(kù)表,這里具體的實(shí)現(xiàn)就是通過(guò)構(gòu)造函數(shù)來(lái)進(jìn)行注入的,具體請(qǐng)參考下面的實(shí)例。

public DegradedVehicleContractService(IObjectMapper objectMapper,
 IRepository<DegradedVehicleContract> degradedVehicleContractRepository,
 IRepository<Product> productRepository,
 IRepository<VehicleInformation> vehicleInformationRepository,
 IRepository<Company> companyRepository,
 IDegradedVehicleContractManager degradedVehicleContractManager,
 IRepository<ProductAffiProductCategory> productAffiProductCategoryRepository,
 IRepository<ProductCategoryBusinessDomain> productCategoryBusinessDomainRepository,
 IRepository<TiledProductCategory> tiledProductCategoryRepository,
 IRepository<BusinessDomain> businessDomainRepository,
 IMapper autoMapper) {
 _objectMapper = objectMapper;
 _degradedVehicleContractRepository = degradedVehicleContractRepository;
 _productRepository = productRepository;
 _vehicleInformationRepository = vehicleInformationRepository;
 _companyRepository = companyRepository;
 _degradedVehicleContractManager = degradedVehicleContractManager;
 _productAffiProductCategoryRepository = productAffiProductCategoryRepository;
 _productCategoryBusinessDomainRepository = productCategoryBusinessDomainRepository;
 _tiledProductCategoryRepository = tiledProductCategoryRepository;
 _businessDomainRepository = businessDomainRepository;
 _autoMapper = autoMapper;
 }

  有了上面的注釋?zhuān)嘈拍銓?duì)上面那部分代碼可以有更加深入的理解,回到正題,這里到底是Product實(shí)體中的問(wèn)題還是VehicleInformation實(shí)體中存在問(wèn)題呢?我們首先將

join vehicleDict in _vehicleInformationRepository.GetAll().Where(v => vinLists.Contains(v.Vin))   on detail.Vin equals vehicleDict.Vin

  這個(gè)部分注釋掉,然后再調(diào)試代碼,我們發(fā)現(xiàn)代碼竟然不報(bào)錯(cuò)了,然后初步判斷VehicleInformation這張表里面有問(wèn)題,然后我們接著注釋掉第二部分而保留第三部分,其中注釋的部分代碼為:

join product in _productRepository.GetAll().Where(p => productIds.Contains(p.Id)) on detail.ProductId equals product.Id

  經(jīng)過(guò)這部分的操作以后,我們發(fā)現(xiàn)執(zhí)行報(bào)錯(cuò),有了這兩步的驗(yàn)證之后我們更加確認(rèn)是VehicleInformation表中存在類(lèi)型不匹配的問(wèn)題,然后我們接著往下進(jìn)行分析。

  2.3 定位報(bào)錯(cuò)字段

  既然報(bào)錯(cuò)信息中是SqlTypes.SqlString'和SqlTypes.SqlGuid之間的轉(zhuǎn)換有問(wèn)題那么我們斷定有一個(gè)字段數(shù)據(jù)庫(kù)中定義的類(lèi)型和實(shí)體中定義的類(lèi)型不匹配,而且其中有一種是guid類(lèi)型,由于我們的實(shí)體中g(shù)uid類(lèi)型的字段要少于string類(lèi)型的字段,所以我們首先從guid類(lèi)型下手,我們看看VehicleInformation中是否有哪種guid類(lèi)型和數(shù)據(jù)庫(kù)不匹配。然后還真的發(fā)現(xiàn)了這個(gè)類(lèi)型 public Guid UnionId { get; set; },在我們的實(shí)體中定義了一個(gè)guid類(lèi)型的字段UnionId這個(gè)是在遷移過(guò)程遷移到數(shù)據(jù)庫(kù)的,然后我們來(lái)查看數(shù)據(jù)庫(kù)中的類(lèi)型。

  通過(guò)查詢數(shù)據(jù)庫(kù)我們發(fā)現(xiàn)數(shù)據(jù)庫(kù)中字段UnionId被定義成了varchar(50)類(lèi)型,明顯在和代碼中g(shù)uid類(lèi)型進(jìn)行匹配的時(shí)候會(huì)發(fā)生錯(cuò)誤,后來(lái)我很疑惑我們的開(kāi)發(fā)模式是采用Code First來(lái)進(jìn)行開(kāi)發(fā)的,現(xiàn)有實(shí)體然后再通過(guò)Migration進(jìn)行數(shù)據(jù)庫(kù)遷移的,應(yīng)該不會(huì)出現(xiàn)這樣的錯(cuò)誤,事后得知是另外一位同事在開(kāi)發(fā)的過(guò)程中手動(dòng)去更改了這個(gè)實(shí)體的類(lèi)型從而導(dǎo)致了這個(gè)問(wèn)題,最后更改數(shù)據(jù)庫(kù)UnionId字段類(lèi)型,然后發(fā)現(xiàn)錯(cuò)誤消失,至此問(wèn)題解決。

總結(jié)

  這篇文章寫(xiě)作的主要目的是如果從一個(gè)大致方向來(lái)一步步去縮小錯(cuò)誤范圍,最終來(lái)一步步找出錯(cuò)誤的根源,最終來(lái)解決問(wèn)題,在這個(gè)過(guò)程中通過(guò)注釋掉部分代碼來(lái)縮小判斷范圍確實(shí)非常有用,另外用到的一個(gè)重要的知道思想就是“大膽假設(shè)小心求證”的思想來(lái)一步步分析問(wèn)題,然后找到問(wèn)題的根源,最終解決問(wèn)題,所以有了上述分析問(wèn)題解決問(wèn)題的方法,我們就能夠以后解決這一類(lèi)型的問(wèn)題,真正做到掌握這一類(lèi)型問(wèn)題的解決方法。

以上就是記一次EFCore類(lèi)型轉(zhuǎn)換錯(cuò)誤及解決方案的詳細(xì)內(nèi)容,更多關(guān)于EFCore類(lèi)型轉(zhuǎn)換錯(cuò)誤及解決方案的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論