Fixed that caching Core Data entities in Dictionaries didn't really work. Setting now Core Data Ids on BankingUi model classes and retrieving Core Data entities by that ID

This commit is contained in:
dankito 2020-09-01 14:22:04 +02:00
parent b6561debb0
commit b4e712f6b8
4 changed files with 63 additions and 28 deletions

View File

@ -1,6 +1,7 @@
package net.dankito.banking.ui.model.tan
import net.dankito.banking.ui.model.Displayable
import net.dankito.utils.multiplatform.UUID
open class TanProcedure(
@ -18,6 +19,9 @@ open class TanProcedure(
val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric
open var technicalId: String = UUID.random()
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TanProcedure) return false

View File

@ -26,11 +26,30 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
context.insert(mapped)
try context.save()
setIds(customer, mapped)
} catch {
NSLog("Could not save Customer \(customer): \(error)")
}
}
private func setIds(_ customer: Customer, _ mappedCustomer: PersistedCustomer) {
customer.technicalId = mappedCustomer.objectIDAsString
for account in customer.accounts {
if let mappedAccount = mappedCustomer.accounts?.first { ($0 as! PersistedBankAccount).identifier == account.identifier} as? PersistedBankAccount {
account.technicalId = mappedAccount.objectIDAsString
}
}
for tanProcedure in customer.supportedTanProcedures {
if let mappedTanProcedure = mappedCustomer.supportedTanProcedures?.first { ($0 as! PersistedTanProcedure).bankInternalProcedureCode == tanProcedure.bankInternalProcedureCode } as? PersistedTanProcedure {
tanProcedure.technicalId = mappedTanProcedure.objectIDAsString
}
}
}
func readPersistedAccounts_() -> [Customer] {
var customers: [PersistedCustomer] = []

View File

@ -4,16 +4,6 @@ import BankingUiSwift
class Mapper {
/* Cache mapped object to not save them twice */
private var mappedBanks = [Customer:PersistedCustomer]()
private var mappedAccounts = [BankAccount:PersistedBankAccount]()
private var mappedTransactions = [AccountTransaction:PersistedAccountTransaction]()
private var mappedTanProcedures = [TanProcedure:PersistedTanProcedure]()
func map(_ customer: PersistedCustomer) -> Customer {
let mapped = Customer(bankCode: map(customer.bankCode), customerId: map(customer.customerId), password: map(customer.password), finTsServerAddress: map(customer.finTsServerAddress), bankName: map(customer.bankName), bic: map(customer.bic), customerName: map(customer.customerName), userId: map(customer.userId), iconUrl: customer.iconUrl, accounts: [])
@ -28,13 +18,11 @@ class Mapper {
mapped.technicalId = customer.objectIDAsString
mappedBanks[mapped] = customer
return mapped
}
func map(_ customer: Customer, _ context: NSManagedObjectContext) -> PersistedCustomer {
let mapped = mappedBanks[customer] ?? PersistedCustomer(context: context)
let mapped = context.objectByID(customer.technicalId) ?? PersistedCustomer(context: context)
mapped.bankCode = customer.bankCode
mapped.customerId = customer.customerId
@ -51,8 +39,6 @@ class Mapper {
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
mappedBanks[customer] = mapped
mapped.supportedTanProcedures = NSOrderedSet(array: map(customer.supportedTanProcedures, context))
mapped.selectedTanProcedureCode = customer.selectedTanProcedure?.bankInternalProcedureCode
@ -76,8 +62,6 @@ class Mapper {
mapped.technicalId = account.objectIDAsString
mappedAccounts[mapped] = account
return mapped
}
@ -86,7 +70,7 @@ class Mapper {
}
func map(_ customer: PersistedCustomer, _ account: BankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount {
let mapped = mappedAccounts[account] ?? PersistedBankAccount(context: context)
let mapped = context.objectByID(account.technicalId) ?? PersistedBankAccount(context: context)
mapped.customer = customer
mapped.identifier = account.identifier
@ -112,8 +96,6 @@ class Mapper {
mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context))
mappedAccounts[account] = mapped
return mapped
}
@ -157,7 +139,7 @@ class Mapper {
func map(_ account: BankAccount, _ transaction: PersistedAccountTransaction) -> AccountTransaction {
let mapped = AccountTransaction(bankAccount: account, amount: map(transaction.amount), currency: map(transaction.currency), unparsedUsage: map(transaction.unparsedUsage), bookingDate: map(transaction.bookingDate), otherPartyName: transaction.otherPartyName, otherPartyBankCode: transaction.otherPartyBankCode, otherPartyAccountId: transaction.otherPartyAccountId, bookingText: transaction.bookingText, valueDate: map(transaction.valueDate), statementNumber: Int32(transaction.statementNumber), sequenceNumber: map(transaction.sequenceNumber), openingBalance: map(transaction.openingBalance), closingBalance: map(transaction.closingBalance), endToEndReference: transaction.endToEndReference, customerReference: transaction.customerReference, mandateReference: transaction.mandateReference, creditorIdentifier: transaction.creditorIdentifier, originatorsIdentificationCode: transaction.originatorsIdentificationCode, compensationAmount: transaction.compensationAmount, originalAmount: transaction.originalAmount, sepaUsage: transaction.sepaUsage, deviantOriginator: transaction.deviantOriginator, deviantRecipient: transaction.deviantRecipient, usageWithNoSpecialType: transaction.usageWithNoSpecialType, primaNotaNumber: transaction.primaNotaNumber, textKeySupplement: transaction.textKeySupplement, currencyType: transaction.currencyType, bookingKey: map(transaction.bookingKey), referenceForTheAccountOwner: map(transaction.referenceForTheAccountOwner), referenceOfTheAccountServicingInstitution: transaction.referenceOfTheAccountServicingInstitution, supplementaryDetails: transaction.supplementaryDetails, transactionReferenceNumber: map(transaction.transactionReferenceNumber), relatedReferenceNumber: transaction.relatedReferenceNumber)
mappedTransactions[mapped] = transaction
mapped.technicalId = transaction.objectIDAsString
return mapped
}
@ -168,7 +150,7 @@ class Mapper {
}
func map(_ account: PersistedBankAccount, _ transaction: AccountTransaction, _ context: NSManagedObjectContext) -> PersistedAccountTransaction {
let mapped = mappedTransactions[transaction] ?? PersistedAccountTransaction(context: context)
let mapped = context.objectByID(transaction.technicalId) ?? PersistedAccountTransaction(context: context)
mapped.account = account
@ -210,8 +192,6 @@ class Mapper {
mapped.transactionReferenceNumber = transaction.transactionReferenceNumber
mapped.relatedReferenceNumber = transaction.relatedReferenceNumber
mappedTransactions[transaction] = mapped
return mapped
}
@ -229,7 +209,7 @@ class Mapper {
allowedTanFormat: tanProcedure.allowedTanFormat == "numeric" ? .numeric : .alphanumeric
)
mappedTanProcedures[mapped] = tanProcedure
mapped.technicalId = tanProcedure.objectIDAsString
return mapped
}
@ -239,7 +219,7 @@ class Mapper {
}
func map(_ tanProcedure: TanProcedure, _ context: NSManagedObjectContext) -> PersistedTanProcedure {
let mapped = mappedTanProcedures[tanProcedure] ?? PersistedTanProcedure(context: context)
let mapped = context.objectByID(tanProcedure.technicalId) ?? PersistedTanProcedure(context: context)
mapped.displayName = tanProcedure.displayName
mapped.type = tanProcedure.type.name
@ -248,8 +228,6 @@ class Mapper {
mapped.maxTanInputLength = map(tanProcedure.maxTanInputLength) ?? -1
mapped.allowedTanFormat = tanProcedure.allowedTanFormat.name
mappedTanProcedures[tanProcedure] = mapped
return mapped
}

View File

@ -1,4 +1,5 @@
import SwiftUI
import CoreData
extension String {
@ -39,6 +40,11 @@ extension String {
return String(self[startIndex...endIndex])
}
var isCoreDataId: Bool {
return self.starts(with: "x-coredata://")
}
}
extension Optional where Wrapped == String {
@ -171,3 +177,31 @@ extension URL {
}
}
extension NSManagedObject {
var objectIDAsString: String {
return self.objectID.uriRepresentation().absoluteString
}
}
extension NSManagedObjectContext {
func objectByID<T : NSManagedObject>(_ objectID: String) -> T? {
if objectID.isCoreDataId {
if let url = URL(string: objectID) {
if let managedObjectId = self.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: url) {
let object = try? self.existingObject(with: managedObjectId) as? T
if object?.isFault == false {
return object
}
}
}
}
return nil
}
}