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:
parent
b6561debb0
commit
b4e712f6b8
|
@ -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
|
||||||
|
|
|
@ -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] = []
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue