0

I get data from a database by using telerik openaccess ORM. I store these in a list by using ToList() method.

Then I use a Parallel.ForEach to map the model objects to DTO objects by using AutoMapper.

An error occurs in the Parallel.ForEach after the first or second treatment in the loop:

DataStoreException: System.InvalidOperationException: Invalid attempt to call IsDBNull when reader is closed.
   at System.Data.SqlClient.SqlDataReader.CheckHeaderIsReady(Int32 columnIndex, Boolean permitAsync, String methodName)
   at System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i)
   at OpenAccessRuntime.Data.IntConverter.Read(DataHolder& data)
   at OpenAccessRuntime.Relational.RelationalGenericOID.CopyKeyFields(DataHolder& data)
   at OpenAccessRuntime.Relational.fetch.FopGetOID.fetch(FetchResult fetchResult, StateContainer stateContainer)
   at OpenAccessRuntime.Relational.fetch.FetchSpec.createRow(FetchResult fetchResult, StateContainer stateContainer)

I can admit the connection is not thread safe but why to need this connection yet after using the ToList() method ? All data are supposed to be retrieved after using this method.

Does it exist another way to do it ?

My code:

IEnumerable<Person> persons = database.GetData<Person>().ToList();

var safeList = new ConcurrentBag<PersonDTO>();
Parallel.ForEach(persons, (p) =>
{
    var dto = Mapper.Map<PersonDTO>(p);
    safeList.Add(dto);
});

return safeList.ToList();
profou
  • 197
  • 1
  • 17
  • I would guess either you're not loading them all beforehand or some of the properties in `Person` are lazy loaded. As an aside, I can't imagine your mapping is terribly expensive - I'd be surprised if this gives you any noticeable benefit in performance. – Charles Mager Apr 08 '22 at 08:51
  • 1
    Where are you calling `.ToList();`? You're not calling it before the parallel mapping, so I'd expect you still have an `IQueryable` at that point. – ProgrammingLlama Apr 08 '22 at 08:57
  • @CharlesMager: In Person class, there is different properties as IList<>, ... The mapping takes about 6 seconds. – profou Apr 08 '22 at 09:07
  • @DiplomacyNotWar: You are right, error while copy-paste. I just edited that. – profou Apr 08 '22 at 09:10
  • Could you include the `Person` class in the question? Does it contain any properties of type `IQueryable`? – Theodor Zoulias Apr 08 '22 at 09:17
  • @TheodorZoulias: I used the `Person` class for example but my class owns a great property hierarchy. Does the ORM get data until a given level in the hierarchy with the method `ToList()` for performance reasons ? All properties and sub-properties are of type: IList<>, IEnumerable<>, Stack<> or basic types as float, int, bool, ... – profou Apr 08 '22 at 09:39
  • 1
    If mapping takes 6 seconds, I'd suspect that various properties are loaded lazily and nearly all of that time is taken in database queries. A quick google suggests this is the default behaviour for OpenAccess. This would explain your exception. I wouldn't expect mapping data in memory to take in the order of seconds. – Charles Mager Apr 08 '22 at 09:44
  • @CharlesMager: I think so too. But I'm surprised the `ToList()` method didn't solve my issue given the type of properties. I don't have any `Lazy<>` properties. – profou Apr 08 '22 at 10:02
  • Try to avoid having `IEnumerable` properties, unless it's your intention that these properties should be lazy/deferred. Convert them to arrays or lists, and see if the problem persists. – Theodor Zoulias Apr 08 '22 at 10:06
  • I doubt they'd be of type `Lazy`. You'd be best reading the documentation to work out how it works and how you could eagerly load properties instead. I can't find any docs, any links redirect to [this page](https://www.telerik.com/data-access-sunsetting) stating that the product was discontinued in 2015 and suggesting you use Entity Framework instead. – Charles Mager Apr 08 '22 at 11:01

0 Answers0