简体   繁体   中英

Designing an optional many-to-many relationship with access restrictions in Spring Data JPA / Hibernate

I want to design a simple discount code app, that allows users to keep track of their use of discount codes. I already have an existing "public" list of discount codes that users may use. However, users should also be able register uses of "private" discount codes.

In their simplest form, the tables may look something like this, with corresponding @Entity classes:

discount_usages

╔════╦══════════════════╦═════════╦════════════╦══════════╦═════╗
║ id ║ discount_code_id ║ user_id ║ last_used  ║ num_uses ║ ... ║
╠════╬══════════════════╬═════════╬════════════╬══════════╬═════╣
║  1 ║                2 ║       7 ║ 2019-05-01 ║        3 ║     ║
║  2 ║                1 ║       4 ║ 2019-07-10 ║        1 ║     ║
║  3 ║                3 ║      11 ║ 2019-05-19 ║        2 ║     ║
║  4 ║                2 ║      11 ║ 2019-05-01 ║        1 ║     ║
║  5 ║                2 ║       6 ║ 2019-07-10 ║        1 ║     ║
║  6 ║                1 ║       4 ║ 2019-05-19 ║        2 ║     ║
╚════╩══════════════════╩═════════╩════════════╩══════════╩═════╝

discount_codes

╔════╦═══════╦════════════════╦═════════════════╦═════╗
║ id ║ code  ║    website     ║ expiration-date ║ ... ║
╠════╬═══════╬════════════════╬═════════════════╬═════╣
║  1 ║ t3fj4 ║ somestore.com  ║ 2019-12-31      ║     ║
║  2 ║ ds7do ║ otherstore.com ║ 2019-12-31      ║     ║
║  3 ║ uw7tp ║ thirdstore.com ║ 2020-03-15      ║     ║
╚════╩═══════╩════════════════╩═════════════════╩═════╝

Requirements:

1. I need to show users all available discount_codes , ie all public ones and all private ones they have added/used themselves. However, users should not be able to see codes that other users have added to their own lists.

2. Users should be able to register a purchase from website x during which they used code y. If it's a new discount_code , it should be saved. The usage should be saved to discount_usages as well, as a new row if it's the user's first usage of the discount_code , or by updating the row if the user has previously used the code.

Notes:

  • ( discount_code_id , user_id ) uniquely identifies a row in discount_usages .
  • This may also be modeled as a @ManyToOne relationship if each "private" discount_code gets saved on a separate row for each customer that uses it.

Question:

Is it possible meet these requirements without adding huge amounts of complexity? My first attempt was adding the following to the DiscountCode entity:

@ManyToOne(optional = true) User ownedByUser;

and then in DiscountCodeRepository :

@Query("select d from DiscountCode d where d.ownedByUser.id is null
        or d.ownedByUser.id = :userId")
findAllByOwnedByUserIdOrOwnedByUserIdIsNull(@Param("userId") Long userId);

but the complexity of this increases very fast, and it's easy to make a programming error to accidentally show private codes to the wrong users.

Is it possible meet these requirements without adding huge amounts of complexity?

In my opinion sure you can.

If you worry about future complexity, you could use Specification pattern https://www.martinfowler.com/apsupp/spec.pdf

In your case you can write these rules:

  • all public ones

  • all private ones they have added/used themselves

For code example see here:

https://github.com/iluwatar/java-design-patterns/tree/master/specification

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM