View from Oracle in Entity Framework not adding. Not primary key - sql

I am facing issues to add a view from oracle to entity framework.
First, the error was that can not infer a primary key from the colums, so I add a pk to the view.
Now says that primary key is not valid because a part of it is nullable.
Oracle query:
CREATE VIEW ALERTEST."GET_SPMONITORES"
AS
select
CAST(NVL(procedure_name, '')AS VARCHAR(200)) AS SP
from all_procedures
where object_name = 'PAC_NL_MONITORES' AND procedure_name IS NOT NULL
;
ALTER VIEW GET_SPMONITORES
ADD CONSTRAINT GET_SPMONITORES_PK PRIMARY KEY (SP) DISABLE NOVALIDATE;

I recently came across the same issue, trying to load a VIEW into EF with Oracle doing its best to wreck all of my tests in making a column show as NOT NULL.
I finally was able to do so using this.
Create a new table
CREATE TABLE "KEY_TABLE"
( "MY_KEY" NUMBER NOT NULL ENABLE,
CONSTRAINT "KEY_TABLE_PK" PRIMARY KEY ("MY_KEY")
);
INSERT INTO KEY_TABLE (MY_KEY) VALUES (1);
Then, create a VIEW that will have both your original view and this new table
CREATE VIEW "GET_SPMONITORES_KEY"
AS
select
my_key, sp
from key_table, GET_SPMONITORES
where my_key = 1
This will then give you a view :
describe "GET_SPMONITORES_KEY";
Name Null Type
------ -------- -------------
MY_KEY NOT NULL NUMBER
SP VARCHAR2(200)
You can now import this GET_SPMONITORES_KEY into EF and thoroughly ignore the my_key column afterwards. You will be able to use this view in any LINQ to SQL statements without any issues.
I have a view that returns the id (PK) of 3 separate tables and I'm able to link them to their corresponding tables in my LINQ to SQL statements so I can return their corresponding EntityObjects.
Hope this helps

You can cheat here a little bit. You don't have to have a primary key defined in the database. You do, however, need to define the primary key inside Entity Framework for the POCO. Thus, you could just figure out what uniquely identifies a record and then mark the fields that are part of that primary key with either [Key] attribute on the POCO or via Fluent API. If you are auto generating this with T4 templates, you'd have to manually add that to the Fluent API only.
If you're primary key is incorrect, though, it will crash if two records end up with the same key.
A primary key cannot be a nullable field, however. If there is no possible way to uniquely identify this data, I would just return a new Guid() in the view and just rely on that being unique to get around this. Though, I'm not entirely sure how you are using this data, so not sure if that would be a problem in the future.

Related

Moving primary key from int to Guid

In my current project, I have to sync multiple client databases to one server database. I had given a try with Microsoft's sync framework and is not useful in my case. Therefor I have to do sync manually. for that I need to change primary key constraints from int to guid in all the tables.
Problem is this primary keys are also referred as foreign key in other tables.
I had referred below,
Moving from ints to GUIDs as primary keys
I am not good at SQL. I understood the logic but actual implementation is very tough for me.
ALTER TABLE MyTable
ADD GuidCol NVARCHAR(50) NOT NULL,
CONSTRAINT AK_GuidCol UNIQUE(GuidCol)
in above code I tried to add a column GuidCol as unique column after googling a lot. But
I don't know How can I fill values in the newly created column?
How can I make this column as PK after assigning value(s)?
How to make sure that this process won't break existing foreign key constraints?
I don't know How can I fill values in the newly created column?
The link you provided gives a solution:
Create a new column for the guid value in the master table. Use the
uniqueidentifier data type, make it not null with a newid()
default so all existing rows will be populated.
So your code should look like this:
alter table myTable add GuidCol uniqueidentifier not null default newid()
How can I make this column as PK after assigning value(s)? How to
make sure that this process won't break existing foreign key
constraints?
The same answer tells you:
Create new uniqueidentifier columns in the child tables.
Run update statements to build the guild relationships using the
exisitng int relationships to reference the entities.
Drop the original int columns.
Use the same uniqueidentifier type as in previuos statement, but instead of providing defalut, run the update statements joining the tables on existing integer id and set in the child's column the corresponding parent value.
Now you have child-parent relationship established but without constraints on them. Drop int columns and create PK and FK on new guid columns

Entity Framework code-first: querying a view with no primary key

Our customer has given the access to views in which there is no primary key is defined. I know Entity Framework needs a primary key for table to identify.
But for views not having primary key is it still possible to query.
I try to find but always Entity Framework gives error saying:
Error: : EntityType 'ViewWeight' has no key defined. Define the key for this EntityType.
I understand key is important for tables, but for views just to read is there any hack or way to read the values without modifying the view itself.
It's not possible in Entity Framework to have Entities without primary key.
Try to get a possible unique key from the views, combining columns, ... to create a unique primary key.
If is not possible there is a workaround, if is only a queryable view, with out need to do other operations with retrieved values such delete or update. Modify the view to add NEWID() , it will generate a unique GUID ID for each row, use this new column as primary key for your entity.
CREATE VIEW FooView AS
SELECT SELECT NEWID() AS ID,
COLUMN_A,
COLUMN_B
.....
The problem is if you repeat the same query every time you will get different ID for the same row.
Updated
If you can't not modify the view you can use Entity with a raw Sql, create the raw sql as
List<MyView> myViewItems = context.MyView.SqlQuery("SELECT NEWID() AS ID, MyView.* FROM MyView").ToList();
In your models add
public Guid ID { get; set; }
And configure the new property as the primary key.
But be careful, because there is not compilation check with this kind of code.
I create the view which includes a primary key. Ensure that all fields in the view are of a specific data type:
Number(9) rather than Number, use CAST to get the type you want
Then add a disabled primary key constraint. It won't do anything except be recognized by entity framework as a key
alter view emp_view add constraint vemp_pk primary key (empno) disable

Creating a table with a field (with a foreign key) which can reference many tables and maintain referencial integrity?

what is the best way of creating a table which can hold a key to a lot of other tables?
As far as I know I have two options:
1) I create a table with a lot of foreign key fields
2) I create two fields, one which indicates the referenced table and another field which holds the primary key of that table.
The latter has a lot of issues due to the fact there's no way to maintain referential integrity (because there's no foreign key to each table).
Besides a link to this table I want to add a description so I can show all notifications in a grid. By clicking a line in the grid I want to open the corresponding program and fix the issue in that program.
It's a bit hard to explain, perhaps this example explains better:
I need to create a system which handles task/notes/notifications for every program in our business application. We have invoices, sales-orders, deliveries, production-orders, etc
Our software detects that something is wrong which any of these. For instance, if the profits on a sales-order are not high enough the order can't be validated automatically. In this case I want to create a notification for the sales-manager so that he can check out what's wrong with the sales-order.
FYI: Iam using Sybase SQL Anywhere 12.
Does it make any sense?
This can be solved in reverse way. Lets say that you have table Alerts where you are going to put all kind of alerts about bad things happened elsewhere. You may reference this table from ALL other tables in your system and create non-mandatory relationship from them. In short it may look like (i'm using MSSQL syntax):
create table Alerts(
ID int not null identity,
SomeInfoAboutTheProblem varchar(255),
constraint PK_Alerts primary key (ID)
)
create table Invoices(
ID....
AlertID int NULL,
....
constraint FK_Invoices2Alerts foreign key (AlertID) references Alerts(ID)
)
In case you cannot modify your tables with business information you may create "extention" table for Alerts that may store some specific problem information and actual reference to the problematic record. For example:
create table Alerts(
ID int not null identity,
SomeInfoAboutTheProblem varchar(255),
constraint PK_Alerts primary key (ID)
)
create table Alerts_for_Invoices(
AlertID int NOT NULL,
InvoiceID int NOT NULL,
SomeAdditionalInvoiceProblemInfo ....,
constraint FK_Alerts_for_Invoices2Alerts foreign key (AlertID) references(ID),
constraint FK_Alerts_for_Invoices2Invoices foreign key (InvoiceID) references Invoices(ID)
)
To show list of problems you may just select general information from Alerts table while opening the dialog you may select all appropriate information regading the problem.

How can I replace the existing primary key with a new primary key on my table?

I'm working with a legacy SQL Server database which has a core table with a bad primary key.
The key is of type NVARCHAR(50) and contains an application-generated string based on various things in the table. For obvious reasons, I'd like to replace this key with an auto-incrementing (identity) INT column.
This is a huge database and we're upgrading it piece-by-piece. We want to minimize the changes to tables that other components write to. I figured I could change the table without breaking anything by just:
Adding the new Id column to the table and making it nullable
Filling it with unique integers and making it NOT NULL
Dropping the existing primary key while ensuring there's a uniqueness constraint still on that column
Setting the new Id column to be the new primary key and identity
Item 3 is proving very painful. Because this is a core table, there are a lot of other tables with foreign key constraints on it. To drop the existing primary key, it seems I have to delete all these foreign key constraints and create them again afterwards.
Is there an easier way to do this or will I just have to script everything?
Afraid that is the bad news. We just got through a big project of doing the same type of thing, although our head DBA had a few tricks up his sleeve. You might look at something like this to get your scripts generated for the flipping of the switch:
I once did the same thing and basically used the process you describe. Except of course you have to first visit each other table and add new foreign key pointing to the new column in your base table
So the approach I used was
Add a new column with an auto incrementing integer in the base table, ensure it has a unique index on it (to be replaced later by the primary key)
For each foreign key relationship pointing to the base table add a new column in the child table. (note this can result in adding more than one column in the child table if more than one relationship)
For each instance of a key in the child table enter a value into the new foreign key field(s)
Replace your foreign key relationships such that the new column now serves
Make the new column in the base table the primary
Drop the old primary key in the base table and each old foreign key in the
children.
It is doable and not as hard as it might sound at first. The crux is a series of update statements for the children table of the nature
Update child_table
set new_column = (select new_primary from base)
where old_primary = old_foreign

Oracle Database Enforce CHECK on multiple tables

I am trying to enforce a CHECK Constraint in a ORACLE Database on multiple tables
CREATE TABLE RollingStocks (
Id NUMBER,
Name Varchar2(80) NOT NULL,
RollingStockCategoryId NUMBER NOT NULL,
CONSTRAINT Pk_RollingStocks Primary Key (Id),
CONSTRAINT Check_RollingStocks_CategoryId
CHECK ((RollingStockCategoryId IN (SELECT Id FROM FreightWagonTypes))
OR
(RollingStockCategoryId IN (SELECT Id FROM LocomotiveClasses)))
);
...but i get the following error:
*Cause: Subquery is not allowed here in the statement.
*Action: Remove the subquery from the statement.
Can you help me understanding what is the problem or how to achieve the same result?
Check constraints are very limited in Oracle. To do a check like you propose, you'd have to implement a PL/SQL trigger.
My advise would be to avoid triggers altogether. Implement a stored procedure that modifies the database and includes the checks. Stored procedures are easier to maintain, although they are slightly harder to implement. But changing a front end from direct table access to stored procedure access pays back many times in the long run.
What you are trying to is ensure that the values inserted in one table exist in another table i.e. enforce a foreign key. So that would be :
CREATE TABLE RollingStocks (
...
CONSTRAINT Pk_RollingStocks Primary Key (Id),
CONSTRAINT RollingStocks_CategoryId_FK (RollingStockCategoryId )
REFERENCES FreightWagonTypes (ID)
);
Except that you want to enforce a foreign key which references two tables. This cannot be done.
You have a couple of options. One would be to merge FreightWagonTypes and LocomotiveClasses into a single table. If you need separate tables for other parts of your application then you could build a materialized view for the purposes of enforcing the foreign key. Materialized Views are like tables and can be referenced by foreign keys. This option won't work if the key values for the two tables clash.
Another option is to recognise that the presence of two candidate referenced tables suggests that RollingStock maybe needs to be split into two tables - or perhaps three: a super type and two sub-type tables, that is RollingStock and FreightWagons, Locomotives.
By the way, what about PassengerCoaches, GuardsWagons and RestaurantCars?
Oracle doesn't support complex check constraints like that, unfortunately.
In this case, your best option is to change the data model a bit - add a parent table over FreightWagonTypes and LocomotiveClasses, which will hold all the ids from both of these tables. That way you can add a FK to a single table.