When trying to add a view to the edmx file, nothing happens.
I opened the edmx file using wxl editor and I noticed the following error:
warning 6013: The table/view
'CellularOrders.dbo.V_LINK' does not
have a primary key defined and no
valid primary key could be inferred.
This table/view has been excluded. To
use the entity, you will need to
review your schema, add the correct
keys, and uncomment it.
(importent thing - I didn't and don't need to add the table which the view based on to the edmx. Moreover, the view is only for doing select statements on the data)
So in the db, I updated the T_LINK table and made one of the fields that reflects on the view as primary key. And then, when I tryed again to add the view to the edmx nothing happens again.
How can I solve this??
Is there an option to fix this without doing anything to the table?
Can I add another view that will somehow wrap the old view but with fixed properties?
Just add a column to your view I added a Row_Number to create a key like this
SELECT ISNULL(CAST((row_number() OVER (ORDER BY tab.ENTRYDATE)) AS int), 0)
AS EDMXID,...other columns go on
the tab expression is table alias and the entrydate is just a field needed for row_number built in sql-server func.
you may choose diffrent ways, e.g.
select newid() as MYEDMXID,....so on
Hope Helps
Each table or view added to entity model must have some key. It actually doesn't have to be primary key. If the table doesn't have the primary key defined EF will try to infer a key using simple rule: It will take all non-nullable non-computed non-binary columns and marks them as an entity key. If none such column exist the entity cannot be automatically added and the designer will throw the mentioned warning. Workaround is adding the view manually and selecting the key yourselves but once you do it you cannot use Update from database because it will always overwrite your changes.
Your defined key should be unique otherwise you can have some other problems related to identity map used internally.
You can easily solve this problem by joining your view with any arbitrary table with a primary column. Just make sure that you only grab a single row from the table.
Here is an example:
CREATE VIEW dbo.myView
AS
SELECT
-- This column enables EF-import via designer by enabling PK generation
Id,
-- These columns belong to the view
[Count],
[Sum]
FROM
(
SELECT
COUNT(*) AS [Count]
,SUM(1) AS [Sum]
FROM
dbo.myTable
) TheViewItself
-- Grab a primary key of a single row from atable
INNER JOIN (SELECT TOP 1 Id FROM dbo.TableWithPrimaryKey) Id ON 1 = 1
"ON 1 = 1" join predicate looks odd. But I needed this to convince EF to import the view.
You can set one of your view columns as not Nullable by using "ISNULL" function as following
ALTER VIEW [dbo].[MyView]
AS
SELECT
ISNULL([StringID],'') AS [Id],
[Name]
FROM [Table]
GO
Use a new table only for link with your views, if your have more then 100k rows, EF6 not its better solution ;)
CREATE TABLE dbo.TablePrimate(Id int CONSTRAINT PK_TablePrimate PRIMARY KEY (Id))
go
set nocount on;
DECLARE #i int;
set #i=1
WHILE #i<10000
BEGIN
INSERT dbo.TablePrimate(Id) values(#i)
SET #i = #i + 1
END
--In fews seconds & 1 MB of storage
GO
Now joins with "MyView"
CREATE VIEW dbo.vwTickets
AS
SELECT TP.Id, MyPKView.* FROM (
SELECT ROW_NUMBER() OVER (ORDER BY Ticket) Line, MyView.*
FROM (
select Grupo, App, Ticket, Titulo, FApertura, Estado, Tipo from dbo.vwEvolutivos
union
select Grupo, App, Ticket, Titulo, FApertura, Estado, Tipo from dbo.vwIncidencias
) MyView
) MyPKView
JOIN dbo.TablePrimate TP ON TP.Id = Line
You can create a view in your database and make queries like this in your code:
List<users> _users = _context.users.SqlQuery("SELECT * FROM users_v").ToList<users>();
I tried to add PostgreSQl views for a long time but without success.
Related
This is Entity Framework 6.1.3
The SQL Server table has a two-column composite key.
ID INT Identity(1,1) NOT NULL
VERSION INT NOT NULL
Inserting a new record works because I don't set the ID on my object; I only set the VERSION.
So a new record would look like this:
ID VERSION
1 1
Perfect! The database generates the ID because the column is configured with Identity and my model is decorated with [DatabaseGenerated(DatabaseGeneratedOption.Identity)].
But now I need to insert another row with the same ID but a different VERSION; hence the composite key. So I would expect the second row to be:
ID Version
1 1
1 2 <- second row has same ID and different version
I do need this to work both ways because there is the scenario where a new ID should be auto-generated by the database, and the other scenario where I have the same ID but a different VERSION.
The Problem:
Because my Code-First model has the ID configured with DatabaseGeneratedOption.Identity, when I set the ID property on my object, my SaveChanges generates the insert statement without the ID!
(Diagnostic Tools in VS shows that Entity Framework generated this statement)
ADO.NET: Execute Reader "INSERT [dbo].[T1]([Version], ... VALUES (#0, ...)
Note the omission of ID. Because I explicitly set the ID on my object, I expected to see this statement instead.
INSERT [dbo].[T1]([ID], [Version], ... VALUES (#0, #1, ...)
That's what I'm trying to accomplish.
The question is:
How can I make Entity Framework include that ID column in its generated insert statement in an elegant way?
I don't want to use a stored procedure or hard code a SQL statement or hack the insert statement by 'squeezing in' the column.
If there is no way, I know that I would have to remove the use of Identity altogether and define my own IDs, which I'm trying to avoid.
Also, my SaveChanges() already makes use of SET IDENTITY_INSERT ON/OFF so that isn't any problem.
Here is the relevant part of my model: (I omitted other properties)
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Key, Column(Order = 1)]
public int VERSION { get; set; }
One avenue that I've explored was to reset my DbContext with a twist in OnModelCreating, but that didn't make a difference.
Of course, in that revision I did remove the DatabaseGenerated decorator off my ID property in the class. I inserted this into OnModelCreating:
if (this.AllowIdentityInsert)
{
modelBuilder.Entity<T1>().Property(x => x.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
else
{
modelBuilder.Entity<T1>().Property(x => x.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
If I could successfully control the model by changing the ID property to DatabaseGeneratedOption to None before my SaveChanges, then this could work and be an elegant solution.
Has anyone run into this situation and found a good solution?
Thanks so much for your input or suggestions.
Generally you don't want to use an identity column in that manner but I suppose if you are using a composite key you could. The problem that you will be faced with to insert your second record is that you will have to turn IDENTITY_INSERT on and off. So thinking of the SQL of it here is an example to show you what has to be done to accomplish the task.
IF OBJECT_ID('tempdb..#TblName') IS NOT NULL
BEGIN
DROP TABLE #TblName
END
CREATE TABLE #TblName (
ID INT IDENTITY(1,1) NOT NULL, Version INT NOT NULL
)
INSERT INTO #TblName (Version) VALUES (1)
SET IDENTITY_INSERT #TblName ON
INSERT INTO #TblName (ID, Version) VALUES (1,2)
SET IDENTITY_INSERT #TblName OFF
SELECT *
FROM
#TblName
A more typical design is to actually maintain a log table via a trigger and store the history in it. Because in that table it wouldn't need the identity column simply another INT.
There are a few more 2 table designs to get around the limitation but you may also want to look into creating SQL SEQUENCE https://msdn.microsoft.com/en-us/library/ff878058.aspx and instead of using IDENTITY on the ID column retrieving a SEQUENCE when you need it and always inserting the value. If you use a SEQUENCE you get the added benefit of being able to add another IDENTITY column that will be a local table ID which is typically recommended rather than relying solely on the composite key.
Okay here is (to me) a very interesting way of doing getting around your IDENTITY issue and maintaining a "incremented version". You can use an Update able View instead of directly using your table. You would use 2 SEQUENCES one for ID and one for VersionId and then to get Version you would use ROW_NUMBER() in the view. You could expand this solution by adding INSTEAD OF INSERT/UPDATE trigger to handle setting of the IDS more automatically but I don't generally like triggers. Anyway, here is to me an interesting solution:
CREATE TABLE dbo.yourTable (
TableId INT NOT NULL IDENTITY(1,1)
,Id INT NOT NULL
,VersionId INT NOT NULL
,Col VARCHAR(100) NOT NULL
,PRIMARY KEY (Id, VersionId)
)
GO
CREATE SEQUENCE dbo.SEQ_yourTableIdBy1
START WITH 1
INCREMENT BY 1;
GO
CREATE SEQUENCE dbo.SEQ_yourTableVersionIdBy1
START WITH 1
INCREMENT BY 1;
GO
CREATE VIEW dbo.yourTable_v
AS
SELECT
Id
,VersionId
,Version = ROW_NUMBER() OVER (PARTITION BY Id ORDER BY VersionId)
,Col
,LatestVersion = CASE
WHEN ROW_NUMBER() OVER (PARTITION BY Id ORDER BY VersionId DESC) = 1
THEN 1 ELSE 0 END
FROM
dbo.yourTable
GO
--New Record
INSERT INTO dbo.yourTable_v(Id, VersionId, Col)
VALUES (NEXT VALUE FOR dbo.SEQ_yourTableIdBy1, NEXT VALUE FOR dbo.SEQ_yourTableVersionIdBy1, 'A')
SELECT * FROM dbo.yourTable_v
--Change To Existing Record
INSERT INTO dbo.yourTable_v(Id, VersionId, Col)
VALUES (1, NEXT VALUE FOR dbo.SEQ_yourTableVersionIdBy1, 'B')
SELECT * FROM dbo.yourTable_v
link showing how it works http://rextester.com/GBHG23338
To Make Entity Framework believe the view is a table you may need to change the Key definition and the Entity Type here is a msdn blog on the subject. https://blogs.msdn.microsoft.com/alexj/2009/09/01/tip-34-how-to-work-with-updatable-views/
Benefits:
this isn't going to break if 2 people try to submit simultaneously etc.
Entity Framework will think this is a normal table once you fake it out slightly by following the link.
While it will have VersionId incremented across all records it will still present a nice Version + 1 for use in your application.
And you can easily add a latest version column for use in your application/queries.
I'm trying to import tables and views from an Oracle database using ODAC 12c Release 4 and Visual Studio 2015 with EF 6 into an .edmx model.
I can import most tables and views just fine, but some of them contains errors and I can't figure out how to fix these. Specifically there are two types of errors I'm having trouble with:
Foreign keys with wrong data type. Usually a NUMBER foreign key column connected to a NUMBER(9,0) column. These will be translated to decimal and int32, causing errors.
Views without primary keys.
Previously I have used ODAC 11 with EF 5 where I could solve these errors in the following way:
The import would add the problematic tables to the diagram and point out the error. To fix it all I had to do was to change the datatypes in the model.
To get a primary key I added ROW_NUMBER() AS ID as a column and set it as a primary key with a disabled constraint CONSTRAINT ID_PK PRIMARY KEY (ID) DISABLE. This would let me import the view but I'd still get an error about primary keys being nullable so I created a script that would add Nullable=False for all primary keys. After this everything would work fine.
Trying to import tables and views with these problems using the new software is much more problematic. Instead of importing first and pointing out the errors afterwards, I'm not allowed to import at all. This is where I get stuck for the two problems:
Trying to add tables with this problem will fail without explanation. Nothing will be added to neither diagram, model nor model.store. Adding one table at a time lets me add either end of the problematic foreign key connection but trying to add the other table will just give this error then do nothing:"The model was generated with warnings or errors. Model.edmx. Please see the Error List for more details. These issues must be fixed before running your application."But the error list will be empty. I can't even see what table is causing the problem to help me fix the issue in the database.
Before adding row number as a primary key the view will be added to model.store but commented out with this error:
"Error 6013: The table/view '[ViewName]' does not have a primary key defined and no valid primary key could be inferred. This table/view has been excluded. To use the entity, you will need to review your schema, add the correct keys, and uncomment it."
After adding row number as a primary key I get this error instead:
"Error 13101: Key part 'ID' for type '[ViewName]' is not valid. All parts of the key must be non-nullable."
The view won't be imported at all, giving me no way to fix the problem since Oracle doesn't allow Nullable=False on views. So I can't fix it before importing but I can't import it without fixing it first...
How am I supposed to deal with these problems using ODAC 12c Release 4 and EF 6?
Having to go back to ODAC 11 and Visual Studio 2012 with EF 5 every time I want to import tables and views from the database is getting annoying.
Searching for others with the same problem only gives a few hits and no answers.
EDIT:
I found a work around for the problem with views.
I created a Row_Number table with Row_Number as the only column and joined the view with that. Since the Row_Number from the table is a primary key it will be marked as Nullable=False in the resulting view and can be imported.
Some code to help anyone else with the same problem:
CREATE TABLE "ROW_NUMBER"
( "ROW_NUMBER" NUMBER(9,0) NOT NULL ENABLE,
CONSTRAINT "ROW_NUMBER_PK" PRIMARY KEY ("ROW_NUMBER"));
CREATE OR REPLACE PROCEDURE CREATE_ROW_NUMBER IS
LOOP_ROW_NUMBER NUMBER := 1;
BEGIN
LOOP
INSERT INTO ROW_NUMBER(ROW_NUMBER)
VALUES (LOOP_ROW_NUMBER);
LOOP_ROW_NUMBER := LOOP_ROW_NUMBER + 1;
IF LOOP_ROW_NUMBER > 1000000 THEN
EXIT;
END IF;
END LOOP;
COMMIT;
END CREATE_ROW_NUMBER;
begin
CREATE_ROW_NUMBER;
end;
CREATE OR REPLACE FORCE VIEW New_View (“ID”, [COLUMNS]) AS
SELECT Row_Number.Row_Number, [COLUMNS]
FROM Row_Number INNER JOIN (
SELECT ROWNUM Row_Number, [COLUMNS]
FROM(
SELECT * FROM Table1
UNION
SELECT * FROM Table2
) Original_View ON Row_Number.Row_Number = Original_View.Row_Number;
Nice solution. works perfectly. Here I want to share 3 additions.
a ")" is missing
you can use an already existing view as original view
add "_1" in the alias view name
Query:
CREATE OR REPLACE FORCE VIEW New_View (“ID”, [COLUMNS]) AS
SELECT Row_Number.Row_Number, [COLUMNS]
FROM Row_Number INNER JOIN (
SELECT ROWNUM Row_Number, [COLUMNS]
FROM (SELECT [COLUMNS] FROM Original_View)
) Original_View_1
ON Row_Number.Row_Number = Original_View_1.Row_Number;
A tale of three tables: using Entity Framework 6, I need a user-editable table Disallow to store conflicts between rows of another table Option of type Technology.
Like this:
Technology:
ID, PK, [int], not null
Description, nvarchar(40), not null
Option:
ID, PK, [int], not null
Name, nvarchar(20), not null
ADD CONSTRAINT (FK_Tech) FOREIGN KEY [ID] REFERENCES [Technology] (ID)
Disallow:
ID1, [int], not null
ID2, [int], not null
PRIMARY KEY (ID1, ID2) ASC
ADD CONSTRAINT [FK_Valid1] FOREIGN KEY [ID1] REFERENCES [Option] (ID)
ADD CONSTRAING (FK_Valid2) FOREIGN KEY [ID2] REFERENCES [Option] (ID)
As I understand it, after importing the database into the model the user should be able to add records from the EF model so that e can specify that when choosing technology options, it should be disallowed to choose two particular options together.
I have spent much time looking for help on using multiple foreign keys into a single table and was able to create the table successfully in SQL Server and I think I understand the issues there.
But when I attempt to import into EF, an association is shown, on the Options table, but nothing else. How can I add rows if there is no mapping to the table? And then I found a link telling me that there is no way to reference a foreign key. So I added two additional fields, but even after numerous attempts -- following the advice of many links on THAT topic -- failed to bring the table into the model. How can I ensure (1) that the IDs added to the Disallow table are found in Option, and (2) still reference them in EF?
Or perhaps better said, how can I accomplish what I want: rows of conflicts that my code will use to limit the selection of options?
I have two tables as follows:-
Table1:
-------------------------------------
PageID|Content|TitleID(FK)|LanguageID
-------------------------------------
1 |abc |101 |1
2 |xyz |102 |1
--------------------------------------
Table2:
-------------------------
TitleID|Title |LanguageID
-------------------------
101 |Title1|1
102 |Title2|1
------------------------
I don't want to add duplicates in my Table1 (content table). Like.. there can be no two pages with the same title. What check do I need to add in my Insert/Update Stored Procedure? How do I make sure duplicates are never added.
I have tried as follows:-
CREATE PROC InsertUpdatePageContent
(
#PageID int,
#Content nvarchar(2000),
#TitleID int
)
AS
BEGIN
IF(#PageID=-1)
BEGIN
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID = #LANGUAGEID))
BEGIN
INSERT INTO Table1(Content,TitleID)
VALUES(#Content,#TitleID)
END
END
ELSE
BEGIN
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID = #LANGUAGEID))
BEGIN
UPDATE Table1
SET Content = #Content, TitleID = #TitleID
WHERE PAGEID = #PAGEID
END
END
END
Now what is happening is that it is inserting new records alright and won't allow duplicates to be added but when I update its giving me problem.
On my aspx Page I have a drop down list control that is bound to DataSource that returns Table 2 (title table) and I have a text box in which user types Page's content to be stored.
When I update, like lets say I have a row in my Table 1 as shown above with PageID=1.
Now when I am updating this row, like I didn't change the Title from the drop down and only changed Content in the text box, its not updating the record ..and when Stored procedure's Update Query does not execute it displays a Label that says "Page with this title exists already."
So whenever I am updating an existing record that label is displayed on screen.How do I change that IF condition in my Update stored procedure??
EDIT:
#gbn: will that IF condition work in case of update? I mean lets say I am updating the Page with TitleID=1, I changed its content, then when I update, it's gonna execute that IF condition and it still won't update coz TitleID=1 already exits!It will only update if TitleID=1 is not there in Table1. Isn't it? Guess I am getting confused. Please answer. Thanks.
Applying a UNIQUE key constraint on TitleID in Table 1 would ensure that no duplicate values for TitleID get saved into the table.
And as far as your stored procedure's code is concerned, gbn's reply highlights the conditional check to be corrected to make it work.
For Update, you cna put this condition to avoid same titles for multiple pages..
IF NOT EXISTS (SELECT 1 from Table1 where TitleId = #TitleID and PageID <> #PageID) -- This makes sure that there is no 'other page' with same title (updated from UI)
{
UPDATE Table1
SET Content = #Content, TitleID = #TitleID
WHERE PAGEID = #PAGEID
}
This will always return false
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID=LANGUAGEID))
You are comparing a column with itself, it matches = EXISTS
It should be something like
CREATE PROC InsertUpdatePageContent (
#PageID int,
#Content nvarchar(2000),
#TitleID int
)
AS
IF(#PageID=-1)
BEGIN
IF NOT EXISTS (SELECT TitleID FROM Table1 WHERE TitleID=#TitleID)
INSERT INTO Table1(Content,TitleID) VALUES(#Content,#TitleID)
END
ELSE
UPDATE Table1 SET Content= #Content, TitleID=#TitleID WHERE PAGEID=#PAGEID
GO
To protect your data, you should have unique index on TitleID in Table1.
I am not sure I completely understand, but I'll take a shot at it for you. I will assume you can't change your data structure.
First I would put a unique constraint on the Title column in the Table2. Then I would put a unique constraint on the TitleId (FK) in the Table1. This will ensure that you don't have two entries in Table1 with the same title.
Then in the stored procedure I would do the comparison against the parameters being brought in and what exists in the database so that either update or insert is being validated against what's being passed in.
I normally use stored procedures as an API between the relational data model and the object model for some software. I rarely expose database identity columns to stored procedure signatures for applications. Database identity columns get treated differently than unique identifiers that software might use to identify entities. It's hard to help much more without additional information about the rest of the application and other stored procedures that need to work together for your solution.
I have a Winform that has fields need to be filled by a user. All the fields doesn't belong to one table, the data will go to Customer table and CustomerPhone table, so i decided to do multiple inserts. I will insert appropriate data to CustomerPhone first then Insert the rest data to Customer table.
Is it possible to Join an Insert OR Insert a Join? If show me a rough sample, i will be grateful.
Many Thanks
Strictly speaking, you can chain inserts and updates in a single statement using the OUTPUT clause. For example, the code bellow inserts at once into two distinct tables:
create table A (
id_a int not null identity(1,1) primary key,
name varchar(100))
create table B (
id_b int not null identity(1,1) primary key,
id_a int null,
name_hash varbinary(16));
insert into A (name)
output inserted.id_a, hashbytes('MD5', inserted.name)
into B (id_a, name_hash)
values ('Jonathan Doe')
select * from A
select * from B
If you're asking whether you can somehow insert into two tables with one SQL statement: No, you need to do the two separate insert statements.
If you're asking something else, please elaborate..
You can make a view which has those columns and do an insert to the view. Normally, a view which combines multiple tables will not be updateable - however, you can make an instead of trigger which inserts into both tables and/or enforces your business logic.
Here's another link.
This can be a very powerful tool if you use it in an organized way to make a layer of views for both selects and unserts/updates.