I have two tables Employee and Address having one-to-one relationship.
CREATE TABLE EMPLOYEE(
ID BIGINT PRIMARY KEY NOT NULL,
EMP_NAME VARCHAR(50) NOT NULL,
PHONE_ID BIGINT,
DELETED BOOLEAN NOT NULL DEFAULT FALSE,
CONSTRAINT CONSTRAINT1 FOREIGN KEY (PHONE_ID)
REFERENCES PHONE (ID)
)
CREATE TABLE PHONE(
ID BIGINT PRIMARY KEY NOT NULL,
PH_NUMBER VARCHAR(20) NOT NULL,
DELETED BOOLEAN NOT NULL DEFAULT FALSE,
)
I am using Spring Data REST.
Q1. I want to expose a single data rest repository method to update DELETED column for both EMPLOYEE and `PHONE.
Something like below:
TestRepository implements CrudRepository{
#Query(value="update both table query", native=false)
public void updateBoth();
}
Q2. Is doing so even possible using Spring data REST.
PLEASE NOTE: I do not want to use native query, i.e. #Query(value="", native="true")
You have to find the balance between using the framework properly and overusing it.
Spring Data REST is to expose your repositories to HTTP but you can't solve everything with it.
The proper way here is to create a custom Controller and implement the functionality you want with proper transaction management to have the data integrity you need.
Related
I've got two tables - Appointment and User. Appointments can be linked to two different Users - a student and a member of staff. The Appointment table contains two foreign keys: StaffUsername and ExternalID. These reference columns in the User table named Username (the User table's PK) and ExternalID (a UNIQUE index). Here are the table definitions:
CREATE TABLE [dbo].[Appointment]
(
[ID] INT NOT NULL IDENTITY(1,1),
[AppointmentTypeID] INT NOT NULL,
[StartTime] DATETIME NOT NULL,
[EndTime] DATETIME NOT NULL,
[AppointmentSlotID] INT NULL,
[StaffUsername] NVARCHAR(200) NOT NULL,
[ExternalID] NVARCHAR(10) NULL,
[BookedBy] NVARCHAR(200) NOT NULL,
[BookedTimestamp] DATETIME NOT NULL,
[ReminderEmailSentTimestamp] DATETIME NULL,
[CancelledBy] NVARCHAR(200) NULL,
[CancelledTimestamp] DATETIME NULL,
[StudentDidNotAttend] BIT NULL,
[LastModifiedTimestamp] DATETIME NOT NULL,
[LastModifiedBy] NVARCHAR(200) NOT NULL,
CONSTRAINT [PK_Appointment] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [FK_Appointment_AppointmentType] FOREIGN KEY ([AppointmentTypeID]) REFERENCES [dbo].[AppointmentType]([ID]),
CONSTRAINT [FK_Appointment_AppointmentSlot] FOREIGN KEY ([AppointmentSlotID]) REFERENCES [dbo].[AppointmentSlot]([ID]),
CONSTRAINT [FK_Appointment_User_StaffUsername] FOREIGN KEY ([StaffUsername]) REFERENCES [dbo].[User]([Username]),
CONSTRAINT [FK_Appointment_User_ExternalID] FOREIGN KEY ([ExternalID]) REFERENCES [dbo].[User]([ExternalID])
)
CREATE TABLE [dbo].[User]
(
[Username] NVARCHAR(200) NOT NULL,
[FirstName] NVARCHAR(200) NULL,
[LastName] NVARCHAR(200) NULL,
[EmailAddress] NVARCHAR(200) NULL,
[IsStaff] BIT NOT NULL DEFAULT 0,
[ExternalID] NVARCHAR(10) NOT NULL,
[LastLogin] DATETIME NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Username] ASC),
CONSTRAINT [UQ_ExternalID] UNIQUE ([ExternalID])
)
Unfortunately, when I use the Update model from database option in the EDMX model designer, it will not pick up the foreign key on the ExternalID columns. It remains looking like this (highlighted in green are the properties relating to the relationship which is modelled correctly, in yellow are the properties which should relate to a second relationship but are being ignored):
I know from experience that the EDMX designer can be quirky at times, especially when detecting changes to objects, so I've tried all the usual tricks. I've checked in Web.config that my connection string is pointing to the correct database. I've deleted the Appointment and User tables in the designer completely and run the Update command again. I've tried that with a save and restart of Visual Studio between deletion and update, too.
To check the relationship is correct in the database I've created a database diagram in SSMS which shows the troublesome relationship correctly:
I've also created a brand new project and added a new Entity Data Model pointing to the same database with the same credentials, just in case the issue was related to the fact that I'm updating an existing model, but no dice. Even in the new project, the relationship isn't detected.
I also tried to create the Navigation Property manually, but as you can see from this screenshot, the foreign key I'd need to select isn't available in the dropdown list:
I don't know if the issue somehow relates to the fact that the ExternalID column isn't the primary key of the User table, or maybe its NVARCHAR(10) data type. I've no idea, to be honest.
Any suggestions as to why this foreign key isn't being detected? And how I can fix it? My project targets .NET Framework 4.6 and I'm using EF6. Obviously I'm using Database First.
In EF6 an Entity only has one key, and so all Navigation Properties must use a Foreign Key that references the same key. EF Core supports Alternate Keys, and supports a Database-First workflow with Reverse Engineering.
I know there are dozens of tutorials for how to do this across just as many websites, but this is my first time trying to connect a database table to a UI, so when the version of Spring Boot/MyBatis/Vaadin, for example, are different than the one I'm working with, or they use JPA or JDBC instead of MyBatis, I have no idea how to change it to work with my specific situation.
When people say "it's no different than any other method of doing it with " that doesn't help AT ALL, since, as I stated earlier, I've never done it before. Annotations and classes in the code examples of a tutorial get removed and deprecated with every new version with no clear explanation of how to change it to work with the newer version. I've been researching the various APIs (Spring Boot, Vaadin, MyBatis) for about a month and have a vague understanding of what each one does but not how they work together to achieve the desired result of making a UI for a database. I'm just getting really frustrated at how a single deprecated annotation or class in a tutorial can bring the whole thing crashing down. I know that was long-winded but I just wanted you all to understand where I'm coming from. I'm not particularly attached to any single API, just whatever is easiest.
My current dependencies are:
- Maven : 4.0.0
- Spring Boot: 2.1.2.RELEASE
- Vaadin: 12.0.4
- MyBatis Spring Boot Starter: 2.0.0
I got the starter package from Spring Initializr and added the MyBatis dependency later.
I have a PostgreSQL 10.5 database with 17 tables that will eventually be a UI for a store manager to use for things like looking at received inventory shipments, the hours an employee worked, and other tasks.
My database is named 'store', user: 'store', password: 'store' (if it matters).
For example, these are a few of my tables:
CREATE TABLE IF NOT EXISTS supplier (
id SERIAL,
brand VARCHAR(30) NOT NULL,
phone VARCHAR(15) NOT NULL,
address VARCHAR(100) NOT NULL,
CONSTRAINT pk_supplier PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS shipment (
id SERIAL,
shipdate DATE NOT NULL,
shiptime TIME NOT NULL,
status VARCHAR(10) DEFAULT 'arrived' NOT NULL,
sid INT NOT NULL,
CONSTRAINT pk_shipment PRIMARY KEY (id),
CONSTRAINT fk_shipment_supplier FOREIGN KEY (sid)
REFERENCES supplier(id)
);
CREATE TABLE IF NOT EXISTS shipmentcontains (
shipid INT NOT NULL,
iid INT NOT NULL,
quantity INT NOT NULL,
price DEC(6,2) NOT NULL,
CONSTRAINT pk_shipmentcontains PRIMARY KEY (shipid, iid),
CONSTRAINT fk_shipmentcontains_shipment FOREIGN KEY (shipid)
REFERENCES shipment(id),
CONSTRAINT fk_shipmentcontains_item FOREIGN KEY (iid)
REFERENCES item(id)
);
CREATE TABLE IF NOT EXISTS item (
id SERIAL,
itemtype VARCHAR(25) NOT NULL,
itemsize VARCHAR(10) NOT NULL,
price DEC(5,2) NOT NULL,
sid INT NOT NULL,
CONSTRAINT pk_item PRIMARY KEY (id),
CONSTRAINT fk_item_supplier FOREIGN KEY (sid)
REFERENCES supplier(id)
);
CREATE TABLE IF NOT EXISTS employee (
id SERIAL,
lastname VARCHAR(40) NOT NULL,
firstname VARCHAR(40) NOT NULL,
hourlywage DEC(4,2),
manager BOOLEAN DEFAULT false NOT NULL,
CONSTRAINT pk_employee PRIMARY KEY (id)
);
If someone can give me a code example of how to just get one of those to show in a Grid, I'm sure I can figure out how to do the rest of it. I have the connection details in my application.properties file, but I've seen that with newer versions of MyBatis this isn't needed and annotations such as #Update can be used on the SQL statements to replace that. Also, in plain English, what the heck is a Spring Bean? I hope that wasn't too long..or not long enough.
EDIT: Current version of Vaadin 12 is 12.0.4
You are asking quite a lot, so I will try to touch everything a little and nothing too detailed. I hope this helps you getting the ball rolling.
First off, you will need a java class with all fields that you have in the supplier table, annotated with #Entity. The #Table annotation lets you define the Db table name, and it is not necessary if the table is called the same as the class (case insensitive):
#Entity // javax.persistence
#Table(name = "supplier") // javax.persistence
public class Supplier {
#Id // javax.persistence
private Long id;
private String brand;
private String phone;
private String address;
public Supplier(){
}
// public getters and setters for all fields
// omitted for brevity
}
Now that you have a class for your table, you can start with creating a Vaadin Grid for it. This can be done the easiest with Grid<Supplier> supplierGrid = new Grid<Supplier>(Supplier.class);.
Now to fill the grid with items (suppliers). This is done with supplierGrid.setItems(allSuppliers);. But where do allSuppliers come from you ask?
They can be fetched using a Repository. Because the repository will be annotated with #Repository, its a spring component that can be automatically generated by spring and can be Injected/Autowired (i.e. in your view) using #Inject/#Autowired.
Then you simply call List<Supplier> allSuppliers = supplierRepository.findAll() and you have a list of all suppliers from your DB, that you now can put into the grid with the aforementioned supplierGrid.setItems(allSuppliers);
Any class where an instance of it can be injected by spring is a spring-bean, this includes classes annotated with either #Component, #Serivce or #Repository. Entities like Supplier can not automatically be injected by Spring, unless you define this is your #Configuration class:
/* Do this only if you want to inject a Supplier somewhere. */
#Bean
public Supplier supplier(){
/* define here how a default Supplier should look like */
return new Supplier();
}
I'm trying to implement an Audit table design in PostgreSQL, where I have different types of user id's that can be audited.
Let's say I have a table named admins (which belong to an organization), and table superadmins (which don't).
CREATE TABLE example.organizations (
id SERIAL UNIQUE,
company_name varchar(50) NOT NULL UNIQUE,
phone varchar(20) NOT NULL check (phone ~ '^[0-9]+$')
);
and an example of a potential admin design
CREATE TABLE example.admins (
id serial primary_key,
admin_type varchar not null,
#... shared data
check constraint admin_type in ("super_admins", "regular_admins")
);
CREATE TABLE example.regular_admins (
id integer primary key,
admin_type varchar not null default "regular_admins"
organization_id integer references example.organizations(id),
#... other regular admin fields
foreign key (id, admin_type) references example.admins (id, admin_type),
check constraint admin_type = "regular_admins"
);
CREATE TABLE example.super_admins (
id integer primary key,
admin_type varchar not null default "super_admins"
#... other super admin fields
foreign key (id, admin_type) references example.admins (id, admin_type),
check constraint admin_type = "super_admins"
);
Now an audit table
CREATE TABLE audit.organizations (
audit_timestamp timestamp not null default now(),
operation text,
admin_id integer primary key,
before jsonb,
after jsonb,
);
This calls for inheritance or polymorphism at some level, but I'm curious about how to design it. I've heard that using PostgreSQL's inheritance functionality is not always a great way to go, although I'm finding it to fit this use case.
I'll need to be able to reference a single admin id in the trigger that updates the audit table, and it would be nice to be able to get the admin information when selecting from the audit table without using multiple queries.
Would it be better to use PostgreSQL inheritance or are there other ideas I haven't considered?
I wouldn't say that it calls for inheritance or polymorphism. Admins and superadmins are both types of user, whose only difference is that the former belong to an organization. You can represent this with a single table and a nullable foreign key. No need to overcomplicate matters. Especially if you're using a serial as your primary key type: bad things happen if you confuse admin #2 for superadmin #2.
I'm develop based on jpa 2.0 with Eclipse Luna, I see that for a composite pk JPA TOOL always generate a pk class as a property of the parent entity, but for some reason I wanna multiple pure properties for composite pk in entity, no need for a pk class.
pls take a look at what I have done.
then entity codes generated as below:
the ddl of table user_info(mysql) is as below:
CREATE TABLE `user_info` (
`first_name` varchar(255) NOT NULL,
`last_name` varchar(255) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`birth_date` datetime DEFAULT NULL,
PRIMARY KEY (`first_name`,`last_name`)
)
what I want is no pk class to generate ,only the entity class with simple type pk fields like only one-field pk,it should look like :
but jpa tool plugin doesn't give me a chance to select the pk generating way, how can I implement it with jpa tool or any other plugin?
Thanks
Kurt
In EF Code First, we can create one-to-one relationship by coding like this:
public class User
{
public int UserID {get;set;}
public string Name {get;set;}
public int UserDetailID {get;set;}
public UserDetail Detail {get;set;}
}
public class UserDetail
{
public int UserDetailID {get;set;}
public string Address {get;set:}
public int UserID {get;set;}
public User User {get;set;}
}
However, when I tried to create the same relationship by using EF Database first in visual studio 2012, I got in trouble. Here is my code:
CREATE TABLE [dbo].[Users] (
[UserID] UNIQUEIDENTIFIER CONSTRAINT [DF_Users_UserID] DEFAULT (newid()) NOT NULL,
[UserDetailID] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([UserID] ASC),
CONSTRAINT [FK_Users_UserDetails] FOREIGN KEY ([UserDetailID]) REFERENCES [UserDetails]([UserDetailID])
);
CREATE TABLE [dbo].UserDetails] (
[UserDetailID] UNIQUEIDENTIFIER CONSTRAINT [DF_UserDetails_UserDetailID] DEFAULT (newid()) NOT NULL,
[UserID] UNIQUEIDENTIFIER NOT NULL,
[Address] NVARCHAR(100) NOT NULL,
CONSTRAINT [PK_UserDetails] PRIMARY KEY CLUSTERED ([UserDetailID] ASC),
CONSTRAINT [FK_UserDetails_Users] FOREIGN KEY ([UserID]) REFERENCES [dbo].[Users] ([UserID])
The error message is something like
"Error 2 SQL01767: Foreign key 'FK_Users_UserDetails' references invalid table 'UserDetails'.
I think the reason for this error probably be when it tries to reference the foreign key "UserDetailID", it finds that it hasn't been created yet. But I don't know how to fix this, and I don't even know this is the way to do it, I know doing one-to-one relationship with EF is tricky, or some people even says it's impossible. Can anyone give me any suggestion? Thank you.
Update: Just to clarify my case, I am trying to design the database in visual studio 2012 database project, then publish it to the SQL server, afterward, create/update my .edmx file from the database in SQL server. I am not sure about how to create a one-to-one relationship that the EF can recognize correctly and create the right classes in .edmx file.
Creating a 1:1 relationship is not that tricky and certainly not impossible, although it is not a particularly common requirement and in this case I can't see why you would want it? If people are saying this then you are talking to the wrong people.
Anyhow using SQL queries as you seem to be is not to do with EF, you are just working directly with the database, In the first CREATE you are trying to add the constraint but you haven't created the other table yet... As you mentioned in your question.
I think you need to create both tables first and then add the constraint with ALTER TABLE.
Additionally searching SO for questions about 1:1 turns up quite a lot so I suggest you do that.
EDIT: So using a database project (I only have VS Express so I don't have those) you want to create a "1:1" relationship using SQL and then add an Entity Data Model to a (probably different) project which references the database and automatically create 1:1 relationship?
That is a whole different story unfortunately. When I was talking about possibility to create 1:1 that was in reference to EF only and not to databases as such. It is actually very difficult/impossible as you said to create 1:1 in SQL. I think that it makes sense that in order to insert into a 1:1 realationship you would need to somehow insert into both tables at exactly the same time or fiddle about with disabling constraints briefly when adding rows.
In general there are a few different option.
Don't split the tables unnecessarily. In true 1:1 all data is required so the only reason to split is for performance reasons (e.g partioning) which I would avoid in this case.
Map multiple table to a single entity as show here.
Create a 1:0..1 relationship and enforce you own requirements in the application.
In either option 2 or 3 you can use the following SQL to create a relationship which uses the same PK on the second table as the FK in the relationship.
CREATE TABLE [dbo].[Users] (
[UserID] UNIQUEIDENTIFIER CONSTRAINT [DF_Users_UserID] DEFAULT (newid()) NOT NULL,
[Name] NVARCHAR (50) NOT NULL,
CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([UserID] ASC),
);
CREATE TABLE [dbo].[UserDetails] (
[UserID] UNIQUEIDENTIFIER NOT NULL,
[Address] NVARCHAR(100) NOT NULL,
CONSTRAINT [PK_UserDetails] PRIMARY KEY CLUSTERED ([UserID] ASC),
CONSTRAINT [FK_UserDetails_Users] FOREIGN KEY ([UserID]) REFERENCES [dbo].[Users] ([UserID]) ON DELETE CASCADE
);
I suggest you also use store generated identity as well where you can.
Just remove UserDetailID from the UserDetail table and make UserID both primary key and a foreign key to the UserID column of the User table.
This the correct way to make 1:1 relationships in a database and EF recognizes it and maps the entities appropriately with database-first approach.
The question is a couple years old.. and the ef version wasn't stated.. but one answer is to remove UserDetailID from both tables. UserID should be the only primary key on both tables.
the 'unqieidentifier' (GUID) data type shouldn't pose an issue (opposed to using INT), but you certainly don't want to populate it with newId..