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

View File

@ -26,11 +26,30 @@ class CoreDataBankingPersistence: IBankingPersistence, IRemitteeSearcher {
context.insert(mapped) context.insert(mapped)
try context.save() try context.save()
setIds(customer, mapped)
} catch { } catch {
NSLog("Could not save Customer \(customer): \(error)") 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] { func readPersistedAccounts_() -> [Customer] {
var customers: [PersistedCustomer] = [] var customers: [PersistedCustomer] = []

View File

@ -5,16 +5,6 @@ import BankingUiSwift
class Mapper { 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 { 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: []) 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 mapped.technicalId = customer.objectIDAsString
mappedBanks[mapped] = customer
return mapped return mapped
} }
func map(_ customer: Customer, _ context: NSManagedObjectContext) -> PersistedCustomer { 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.bankCode = customer.bankCode
mapped.customerId = customer.customerId mapped.customerId = customer.customerId
@ -51,8 +39,6 @@ class Mapper {
mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context)) mapped.accounts = NSOrderedSet(array: map(mapped, customer.accounts, context))
mappedBanks[customer] = mapped
mapped.supportedTanProcedures = NSOrderedSet(array: map(customer.supportedTanProcedures, context)) mapped.supportedTanProcedures = NSOrderedSet(array: map(customer.supportedTanProcedures, context))
mapped.selectedTanProcedureCode = customer.selectedTanProcedure?.bankInternalProcedureCode mapped.selectedTanProcedureCode = customer.selectedTanProcedure?.bankInternalProcedureCode
@ -76,8 +62,6 @@ class Mapper {
mapped.technicalId = account.objectIDAsString mapped.technicalId = account.objectIDAsString
mappedAccounts[mapped] = account
return mapped return mapped
} }
@ -86,7 +70,7 @@ class Mapper {
} }
func map(_ customer: PersistedCustomer, _ account: BankAccount, _ context: NSManagedObjectContext) -> PersistedBankAccount { 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.customer = customer
mapped.identifier = account.identifier mapped.identifier = account.identifier
@ -112,8 +96,6 @@ class Mapper {
mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context)) mapped.transactions = NSSet(array: map(mapped, account.bookedTransactions, context))
mappedAccounts[account] = mapped
return mapped return mapped
} }
@ -157,7 +139,7 @@ class Mapper {
func map(_ account: BankAccount, _ transaction: PersistedAccountTransaction) -> AccountTransaction { 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) 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 return mapped
} }
@ -168,7 +150,7 @@ class Mapper {
} }
func map(_ account: PersistedBankAccount, _ transaction: AccountTransaction, _ context: NSManagedObjectContext) -> PersistedAccountTransaction { 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 mapped.account = account
@ -210,8 +192,6 @@ class Mapper {
mapped.transactionReferenceNumber = transaction.transactionReferenceNumber mapped.transactionReferenceNumber = transaction.transactionReferenceNumber
mapped.relatedReferenceNumber = transaction.relatedReferenceNumber mapped.relatedReferenceNumber = transaction.relatedReferenceNumber
mappedTransactions[transaction] = mapped
return mapped return mapped
} }
@ -229,7 +209,7 @@ class Mapper {
allowedTanFormat: tanProcedure.allowedTanFormat == "numeric" ? .numeric : .alphanumeric allowedTanFormat: tanProcedure.allowedTanFormat == "numeric" ? .numeric : .alphanumeric
) )
mappedTanProcedures[mapped] = tanProcedure mapped.technicalId = tanProcedure.objectIDAsString
return mapped return mapped
} }
@ -239,7 +219,7 @@ class Mapper {
} }
func map(_ tanProcedure: TanProcedure, _ context: NSManagedObjectContext) -> PersistedTanProcedure { 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.displayName = tanProcedure.displayName
mapped.type = tanProcedure.type.name mapped.type = tanProcedure.type.name
@ -248,8 +228,6 @@ class Mapper {
mapped.maxTanInputLength = map(tanProcedure.maxTanInputLength) ?? -1 mapped.maxTanInputLength = map(tanProcedure.maxTanInputLength) ?? -1
mapped.allowedTanFormat = tanProcedure.allowedTanFormat.name mapped.allowedTanFormat = tanProcedure.allowedTanFormat.name
mappedTanProcedures[tanProcedure] = mapped
return mapped return mapped
} }

View File

@ -1,4 +1,5 @@
import SwiftUI import SwiftUI
import CoreData
extension String { extension String {
@ -39,6 +40,11 @@ extension String {
return String(self[startIndex...endIndex]) return String(self[startIndex...endIndex])
} }
var isCoreDataId: Bool {
return self.starts(with: "x-coredata://")
}
} }
extension Optional where Wrapped == String { 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
}
}