Как добиться отношений «многие ко многим», используя CDS / BOPF и ассоциации?
Например, рассмотрим, есть ли у вас таблицы для фильмов и жанров, в которых мы хотим назначать жанры для фильмов.
define table zmv_movies {
key client : abap.clnt not null;
key id : snwd_node_key not null;
name : abap.string(0);
release_date : abap.dats;
plot : abap.string(0);
}
define table zmv_genres {
key client : abap.clnt not null;
key id : snwd_node_key not null;
name : abap.string(0);
}
Хороший способ отобразить отношения многие ко многим (n: m) - это соединительные таблицы, поэтому я создал:
define table zmv_moviesgenres {
@AbapCatalog.foreignKey.screenCheck : false
key movie_id : snwd_node_key not null
with foreign key [0..*,1] zmv_movies
where client = syst.mandt
and id = zmv_moviesgenres.movie_id;
@AbapCatalog.foreignKey.screenCheck : false
key genre_id : snwd_node_key not null
with foreign key [0..*,1] zmv_genres
where client = syst.mandt
and id = zmv_moviesgenres.genre_id;
}
Как создать транзакционные представления, которые правильно обрабатывают это?
Мои попытки до сих пор
Я создал рабочий пример, но он не работает по согласованности данных.
Я изменил zmv_moviesgenres
, чтобы иметь собственный первичный ключ:
define table zmv_moviesgenres {
key movie_genre_id : snwd_node_key not null;
@AbapCatalog.foreignKey.screenCheck : false
movie_id : snwd_node_key not null
with foreign key [0..*,1] zmv_movies
where client = syst.mandt
and id = zmv_moviesgenres.movie_id;
@AbapCatalog.foreignKey.screenCheck : false
genre_id : snwd_node_key not null
with foreign key [0..*,1] zmv_genres
where client = syst.mandt
and id = zmv_moviesgenres.genre_id;
}
Затем я создал несколько базовых представлений, а затем транзакционных представлений:
MOVIES_TP:
@AbapCatalog.sqlViewName: 'ZMVIMOVIESTP'
//@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Movies transactional view'
@VDM.viewType: #TRANSACTIONAL
@ObjectModel: {
modelCategory: #BUSINESS_OBJECT,
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
compositionRoot: true,
transactionalProcessingEnabled: true,
writeActivePersistence: 'ZMV_MOVIES',
draftEnabled: true,
writeDraftPersistence: 'ZMVIDMOVIESTP',
semanticKey: 'id'
}
define view ZMVI_Movies_TP
as select from ZMVI_Movies
association [0..*] to ZMVI_Movies_Genres_TP as _movies_genres on $projection.id = _movies_genres.movie_id
{
@ObjectModel.readOnly: true
key id,
@ObjectModel.association.type: [ #TO_COMPOSITION_CHILD ]
_movies_genres,
name,
release_date,
plot
}
MOVIES_GENRES_TP:
@AbapCatalog.sqlViewName: 'ZMVIMOVGENTP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Movies Genres Transactional View'
@VDM.viewType: #TRANSACTIONAL
@ObjectModel: {
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
writeDraftPersistence: 'ZMVDMOVIESGENRES',
writeActivePersistence: 'ZMV_MOVIESGENRES',
semanticKey: 'movie_genre_id',
alternativeKey: [{id: 'movie_id'}]
}
define view ZMVI_Movies_Genres_TP as select from ZMVI_Movies_Genres
association [1..1] to ZMVI_Movies_TP as _movies on $projection.movie_id = _movies.id
association [1..1] to ZMVI_GENRES_TP as _genres on $projection.genre_id = _genres.id
{
key movie_genre_id,
genre_id,
movie_id,
@ObjectModel.association.type: [ #TO_COMPOSITION_PARENT, #TO_COMPOSITION_ROOT ]
_movies,
_genres
}
GENRES_TP:
@AbapCatalog.sqlViewName: 'ZMVIGENRESTP'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Genres transactional view'
@VDM.viewType: #TRANSACTIONAL
@ObjectModel: {
modelCategory: #BUSINESS_OBJECT,
createEnabled: true,
updateEnabled: true,
deleteEnabled: true,
compositionRoot: true,
transactionalProcessingEnabled: true,
writeActivePersistence: 'ZMV_GENRES',
semanticKey: 'id',
alternativeKey: [{element: ['_movies_genres']}]
}
define view ZMVI_GENRES_TP as select from ZMVI_Genres
association [0..*] to ZMVI_Movies_Genres_TP as _movies_genres on $projection.id = _movies_genres.genre_id {
@ObjectModel.readOnly: true
key id,
_movies_genres,
name
}
Это работает.Он связывает фильмы с жанрами.Но если я удаляю жанр, он не проверяет, используется ли жанр в фильме.Я должен был создать определение / подтверждение для этого, чтобы проверить вручную.
Кроме того, он позволяет повторные назначения (например, две строки ["Звездные войны | Научно-фантастические", "Звездные войны | Научно-фантастические"]])
Я использую систему S / 4 1809, компоненты SAP_ABA 75D, SAP_BASIS 753.
Есть ли другой способ сделать это?