JPA-how to Add record to master table and child table? - sql

I am having two tables One is a Master table called TRANSACTION and second is record of the transaction this table is called TRANSACTION_RECORD.
TRANSACTION
CREATE TABLE `e3_transaction` (
`transactionid` bigint(20),
`transactiontype` varchar(10),
`transactionstatus` varchar(10),
PRIMARY KEY (`transactionid`)
);
TRANSACTION_RECORD
CREATE TABLE `e3_as2805msg4` (
`transectionid` bigint(20),
`messageType` int(4),
`cardAcceptorName` varchar(40),
`adNational` varchar(1000),
`adPrivate` varchar(1000),
KEY `transectionidFK` (`transectionid`),
CONSTRAINT `transectionidFK` FOREIGN KEY (`transectionid`) REFERENCES `e3_transaction` (`transactionid`)
);
It will have one to one mapping between Transaction and transaction record. It means one transaction can have only one record. I have kept this table separately for some reasons. So my class will look like this:
#Entity
#Table(name = "e3_transaction")
public class Transaction {
#Id
#GeneratedValue(generator = "assigned-by-code")
#GenericGenerator(name = "assigned-by-code", strategy = "assigned")
#Column(name = "transactionid", unique = true, nullable = false)
private Long transactionid;
#Column(name = "transactiontype", nullable = false, length = 10)
private String transactiontype;
#Column(name = "transactionstatus", nullable = false, length = 10)
private String transactionstatus;
#oneToOne
private TransactionRecord record;
}
I want to persist both objects at a same time. when I persist a TRANSACTION, TRANSACTION_RECORD should be persist in it's table. Is there any way to do this ?
You can change the table structure if you want. Only thing i need it TWO tables.

Works with
#OneToOne(cascade=CascadeType.ALL)
#MapsId
private TransactionRecord record;
TransactionRecord must have an #Id of the same type as Transaction with no value generation.
Tried with Hibernate as JPA 2.0-provider.

There are a few options to map this, but it looks like you are handling it with two separate entities. As both entities share the same primary key value, your reference mapping will need to change based on which entity you wish to have controlling the pk value generation - as it stands, the e3_transaction.transactionid field is being set by two separate mappings; the transactionid long and the TransactionRecord record reference.
If you wish to use the #MapsId as is suggested in the other answer, you will need to move your #GeneratedValue code to the TransactionRecord entity, as the JPA provider will use the value in the referenced TransactionRecord to set the transactionid attribute and the database field. This is a simple elegant solution, but you can also remove the Long transactionid attribute from Transaction and just mark the record reference with #Id (instead of #MapsId). The long transactionId value within TransactionRecord would still be used as Transaction's id for EntityManager getReference and find calls.
A different option that allows keeping the #GeneratedValue on the transactionid within Transaction is to define the #JoinColumn annotation on the record reference and specify that the field is insertable=false, updatable=false. You then need to modify the TransactionRecord so that it has a back relationship to the Transaction so that it can pull the transectionid value from the Transaction instance to use as its id. This can be accomplished by simply marking the relationship with #ID though.

Related

Room insert into one-to-many relationship

When trying to use intermediary classes to model entity relationships in Room, I have run into an issue. Whilst documentation describes how to get from a one-to-many relationship, it does not describe how to insert.
I'm assuming this cannot be done automatically, therefore we need a query to insert the parent, retrieve the ID for the parent and assign it to the child's foreign key, and then insert the child.
The problem is that I am unsure where to put such a query. If I include it in my DAO, then I will have to include superflous methods for inserting the child. If I include it in my Repository, this makes testing very difficult (if not impossible).
Does anyone know how to resolve this?
I'm assuming this cannot be done automatically, therefore we need a query to insert the parent, retrieve the ID for the parent and assign it to the child's foreign key, and then insert the child.
The first assumption is correct, that is that you have to supply the id of the parent (otherwise how is to know the parent).
However the second assumption that you have to query the parent is not always the case and not so in the scenario you describe. If when inserting a parent then the id is returned if using the convenience #Insert as a Long or an array of Longs (if inserting multiple Parents).
For example, say you have :-
#Entity
data class Parent(
#PrimaryKey
var id: Long? = null,
var other: String
)
and
#Entity
data class Child(
#PrimaryKey
var id: Long? = null,
var parentId: Long,
var otherdata: String
)
and an #Dao annotated class with :-
#Insert
fun insert(parent: Parent): Long
#Insert
fun insert(child: Child): Long
Then you can use the following, without having to query the Parent:-
var lastParent = dao.insert(Parent(other = "Parent1 other data"))
dao.insert(Child(parentId = lastParent, otherdata = "Child1 other data"))
dao.insert(Child(parentId = lastParent, otherdata = "Child2 other data"))
// Insert a Child with it's Parent together
dao.insert(Child(
parentId = dao.insert(Parent(other = "Parent2 other data")),
otherdata = "Child3 other data"
))
note even if you define the id's as Int, a Long is returned when inserting.
It is incorrect to use Int for an id as SQLite stores the id as a 64bit signed integer which is to large for an Int.
However, issues would not occur until the id reached a value that is too large for an Int (32bit signed) i.e. greater than 2,147,483,647.

Insert strategy for tables with one-to-one relationships in Teradata

In our data model, which is derived from the Teradata industry models, we observe a common pattern, where the superclass and subclass relationships in the logical data model are transformed into one-to-one relationships between the parent and the child table.
I know you can roll-up or roll-down the attributes to end up with a single table but we are not using this option overall. At the end what we have is a model like this:
Where City Id references a Geographical Area Id.
I am struggling with a good strategy to load the records in these tables.
Option 1: I could select the max(Geographical Area Id) and calculate the next Ids for a batch insert and reuse them for the City Table.
Option 2: I could use an Identity column in the Geographical Area Table and retrieve it after I insert every record in order to use it for the City table.
Any other options?
I need to assess the solution in terms of performance, reliability and maintenance.
Any comment will be appreciated.
Kind regards,
Paul
When you say "load the records into these tables", are you talking about a one-time data migration or a function that creates records for new Geographical Area/City?
If you are looking for a surrogate key and are OK with gaps in your ID values, then use an IDENTITY column and specify the NO CYCLE clause, so it doesn't repeat any numbers. Then just pass NULL for the value and let TD handle it.
If you do need sequential IDs, then you can just maintain a separate "NextId" table and use that to generate ID values. This is the most flexible way and would make it easier for you to manage your BATCH operations. It requires more code/maintenance on your part, but is more efficient than doing a MAX() + 1 on your data table to get your next ID value. Here's the basic idea:
BEGIN TRANSACTION
Get the "next" ID from a lookup table
Use that value to generate new ID values for your next record(s)
Create your new records
Update the "next" ID value in the lookup table and increment it by the # rows newly inserted (you can capture this by storing the value in the ACTIVITY_COUNT value variable directly after executing your INSERT/MERGE statement)
Make sure to LOCK the lookup table at the beginning of your transaction so it can't be modified until your transaction completes
END TRANSACTION
Here is an example from Postgres, that you can adapt to TD:
CREATE TABLE NextId (
IDType VARCHAR(50) NOT NULL,
NextValue INTEGER NOT NULL,
PRIMARY KEY (IDType)
);
INSERT INTO Users(UserId, UserType)
SELECT
COALESCE(
src.UserId, -- Use UserId if provided (i.e. update existing user)
ROW_NUMBER() OVER(ORDER BY CASE WHEN src.UserId IS NULL THEN 0 ELSE 1 END ASC) +
(id.NextValue - 1) -- Use newly generated UserId (i.e. create new user)
)
AS UserIdFinal,
src.UserType
FROM (
-- Bulk Upsert (get source rows from JSON parameter)
SELECT src.FirstName, src.UserId, src.UserType
FROM JSONB_TO_RECORDSET(pUserDataJSON->'users') AS src(FirstName VARCHAR(100), UserId INTEGER, UserType CHAR(1))
) src
CROSS JOIN (
-- Get next ID value to use
SELECT NextValue
FROM NextId
WHERE IdType = 'User'
FOR UPDATE -- Use "Update" row-lock so it is not read by any other queries also using "Update" row-lock
) id
ON CONFLICT(UserId) DO UPDATE SET
UserType = EXCLUDED.UserType;
-- Increment UserId value
UPDATE NextId
SET NextValue = NextValue + COALESCE(NewUserCount,0)
WHERE IdType = 'User'
;
Just change the locking statement to Teradata syntax (LOCK TABLE NextId FOR WRITE) and add an ACTIVITY_COUNT variable after your INSERT/MERGE to capture the # rows affected. This assumes you're doing all this inside a stored procedure.
Let me know how it goes...

What should I make the type of a "marital status" field?

I have a field in my table "marital status" , the user has to choose (radiobutton) if he's (married, divorced, single, voeuf)
What should I make the type of this field?
Is there a boolean type?
marital status doesn't sound like a boolean anyway. It sounds like an enumeration. A boolean would be married (Y/N), although I think in this day and age you might want to be able to store multiple kinds of relationships in there, and you specified yourself that you need to store 'devorced' as well, so a boolean is out of the question.
So I'd recommend making a table named MaritalStatus, having an ID and a description. Store the various states in there, and make a foreign key to MaritalStatusID in your table.
Make it an INT field , Create another table in your database something like
CREATE TABLE dbo.MaritalStatus
(
M_ID INT PRIMARY KEY NOT NULL,
M_Status NVARCHAR(20)
)
GO
INSERT INTO dbo.MaritalStatus
VALUES
(1, 'Single'),(2,'Married'),(3,'Divorced'),
(4,'Widowed'),(5,'Other'),(6,'Prefer Not to say').... bla bla
Now in your Table in "Marital Status" field refer to a user Marital Status using INT values from dbo.MaritalStatus table's "M_ID".
Boolean or in SQL bit datatype is best when you have a situation where something can be TRUE or NOT TRUE, for someone's Marital Status there can be more than two possible values therefore you should create a separate table for all the possible Marital Status and use Foreign key constraint.
The boolean equivalent for T-SQL is bit.
Though, it seems like you want more than a yes/no answer. In this case use an int and then convert the int to an enum.
Edit: Dukeling removed the C# tag in an edit, so I am not sure how relevant this part is anymore /Edit
The enum:
enum MaritalStatus
{
Single,
Married,
Divorced,
...
}
The int from DB:
int maritalStatusFromDB = //value from DB
Convert int to enum:
MaritalStatus maritalStatus = (MaritalStatus)maritalStatusFromDB;
Be aware that your database may contain int values that are not defined in your enum, such as 10. You can check whether maritalStatusFromDB is a valid MaritalStatus as follows:
bool isValid = Enum.IsDefined(typeof(MaritalStatus), maritalStatusFromDB);
if( isValid == false )
{
//handle appropriately
}

Retrieving Database Schema Linq to SQL VB.Net

I want to retrieve each column name and data type then check if the columns is foreign key then query they key table of that relation !!! could be done ?? I googled for 3 days I know that I have to use Mappping model OR Reflection or both ,,,, but i cant do it .
I will simplify what i need assuming :
TABLE1 hase foreign key( COL3) refer to the primary key (COL1) in TABLE0 :
iterate TABLE1 Columns check EACH columns if it is a foreign key ( also get its data type)
Get the relation to determine the associated table(TABLE0)
retrieve the primary key tables (TABLE0)
I got it
I make a function that return the type of each foreign key and the related table class type
Private Function GetForeignKeyTables(ByVal myTableType As Type) As List(Of myForeignKeys)
Dim myDx = New Tester.DataClasses1DataContext
Dim mymodel As New AttributeMappingSource
Dim myAsociations = mymodel.GetModel(GetType(DataClasses1DataContext)).GetTable(myTableType).RowType.Associations
Dim asc = From m In myAsociations Where m.IsForeignKey
Select New myForeignKeys With {.KeyDataType = m.ThisKey.First.DbType, .RelatedTableType = m.OtherType}
Return asc.ToList
End Function
Private Class myForeignKeys
Property KeyDataType As String
Property RelatedTableType As MetaType
End Class
But I still need to retrieve the data from those related table .
I mean how to create an instance of the class from its MetaType variable?

Adding to the Where clause of an Update in LinQ-to-Entities

Let's say I have a table called Product, with three columns: Id, CustomerId, Name. Id is the primary key. The schema is outside of the control of my group, and we now have a requirement to always provide CustomerId as a parameter for all queries (selects, updates, deletes). It's a long story I'd rather not get into ... it involves triggers :-P
So my question is, when I have an attached entity in LinqToEntities, and I want to save some updates (say I'm updating the name in this case). How can I get it to generate the SQL:
update Product set Name = #Name where Id=#Id and CustomerId=#CustomerId
Where the customerId parameter is included in the where clause in addition to the primary key.
Thanks :-)
Does the CustomerId help uniquely identify the row past #Id? I didn't really follow the "triggers" bit, since the predicate used for the update is not known by the trigger. Or you do want to re-update the CustomerId each time (detectable from UPDATE(...) in the trigger)
The easiest option is to do it as object updates:
var qry = from product in model.Products
where Id == #Id && CustomerId == #CustomerId
select product;
foreach(Product p in qry) {
p.Name = #Name;
}
model.SaveChanges(); // or whatever the method is in EF
If you know you are expecting one record, you could use:
Product prod = (from product in model.Products
where Id == #Id && CustomerId == #CustomerId
select product).Single();
prod.Name = #Name;
mode.SaveChanges(); // ditto
You might also be able to write it as Entity-SQL, but I'm not sure I'd bother, personally... (update: I've just checked, and I don't think Entity-SQL includes DML, so no, you can't - you'd have to use either the above, or a regular SQL command/SPROC)
One way would be to use a stored proc to do the update. This gives you complete control over the SQL.
Another way is to add the CustomerId to the entity key.