private void Save <TId>(TRootEntity rootEntity, out TId lastId, SaveMode saveMode) { if (rootEntity == null) { throw new ArgumentException("rootEntity is null."); } if (_queryOptions.Transaction == null) { throw new InvalidOperationException("Transaction is null."); } Map <TRootEntity> map = new Map <TRootEntity>(_queryOptions); _setMap(map); lastId = default(TId); _databaseAccessor.BeginSave(); List <Row> updateRows = GetRows(rootEntity, map); if (saveMode == SaveMode.Insert) { _databaseAccessor.Insert(updateRows.First(), _queryOptions, out object lastIdObj); if (lastIdObj != null) { lastId = (TId)Convert.ChangeType(lastIdObj, typeof(TId)); } foreach (var updateRow in updateRows.Skip(1)) { _databaseAccessor.Insert(updateRow, _queryOptions, out lastIdObj); } return; } List <TRootEntity> currentEntityList = Fetch().ToList(); if (currentEntityList.Count == 0) { throw new InvalidOperationException("not exists current entity."); } if (currentEntityList.Count != 1) { throw new InvalidOperationException("1 or more current entities."); } List <Row> currentRows = GetRows(currentEntityList.First(), map); if (currentRows.First().Id != updateRows.First().Id) { throw new InvalidOperationException("not match primary values of current entity."); } Dictionary <string, Row> currentRowMap = currentRows.ToDictionary(x => x.Id); Dictionary <string, Row> updateRowMap = updateRows.ToDictionary(x => x.Id); if (saveMode == SaveMode.Update) { _databaseAccessor.Update(updateRows.First(), _queryOptions); foreach (var updateRow in updateRows.Skip(1)) { string id = updateRow.Id; if (currentRowMap.ContainsKey(updateRow.Id)) { _databaseAccessor.Update(updateRow, _queryOptions); } else { _databaseAccessor.Insert(updateRow, _queryOptions, out object lastIdObj); } } foreach (var currentRow in currentRows.Skip(1)) { if (updateRowMap.ContainsKey(currentRow.Id)) { continue; } _databaseAccessor.Delete(currentRow, _queryOptions); } } else { foreach (var updateRow in updateRows) { _databaseAccessor.Delete(updateRow, _queryOptions); } } }