I am developing a C# application with .net version 4.5.2 and an Oracle DB.
The problem I have is that I can't get Entity Framework configured right to the database. The database contains a unique keys over 4 columns, but 2 of them are nullable.
[Key, Column("GEBRUIKER", Order = 0)]
public string User { get; set; }
[Key, Column("EL1", Order = 1)]
public string Element1 { get; set; }
[Key, Column("EL2", Order = 2)]
public short? Element2 { get; set; }
[Key, Column("EL3", Order = 3)]
public short? Element3 { get; set; }
When I try to get the values through this code from the database I get a null reference exception, because element 2 or 3 is empty.
When I remove the Keys from element 2 and 3, I wont get the right data, because when element 1 is the same at 2 rows, the second row will cache element 2 and 3.
Question: How can I handle these nullable unique keys?
Added extra information:
Well, this is a part of the create script of the database:
CREATE TABLE USERS
(
GEBRUIKER VARCHAR2(3 BYTE) NOT NULL,
EL1 VARCHAR2(6 BYTE) NOT NULL,
EL2 NUMBER,
EL3 NUMBER
)
CREATE UNIQUE INDEX USERS_UK ON USERS
(GEBRUIKER, EL1, EL2, EL3)
ALTER TABLE USERS ADD (
CONSTRAINT USERS_UK
UNIQUE (GEBRUIKER, EL1, EL2, EL3)
USING INDEX USERS_UK
ENABLE VALIDATE);
It is not possible to make any changes to the structure or data, because there are multiple applications who use this database. Also there are already EL2 and EL3 rows with the value 0.
Example data:
{'USER1','A','A','C'}
{'USER1','A','B','B'}
{'USER1','B','A','C'}
When I do a linq query to select USER1 AND EL1 = A I will get the next result:
{'USER1','A','A','C'}
{'USER1','A','A','C'}
instead of:
{'USER1','A','A','C'}
{'USER1','A','B','B'}
No, you can not do that:
Look to your table creation SQL:
CREATE TABLE [dbo].[Users](
[GEBRUIKER] [nvarchar](128) NOT NULL,
[EL1] [nvarchar](128) NOT NULL,
[EL2] [smallint] NOT NULL,
[EL3] [smallint] NOT NULL,
CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED
(
[GEBRUIKER] ASC,
[EL1] ASC,
[EL2] ASC,
[EL3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
All primary keys are Not Null!!!!
let say you want to hack this key and change it by your self with SQL then you have to send the following script which will changes the key from nun nullable to nullabe!
usersDatabaseContext.Database.ExecuteSqlCommand(#"
while(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='FOREIGN KEY'))
begin
declare #sql nvarchar(2000)
SELECT TOP 1 #sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[TableName] DROP CONSTRAINT [' + CONSTRAINT_NAME + ']')
FROM information_schema.table_constraints
WHERE CONSTRAINT_TYPE = 'FOREIGN KEY'
exec (#sql)
end
ALTER TABLE Users DROP CONSTRAINT [PK_dbo.Users]
ALTER TABLE Users ALTER COLUMN EL2 SMALLINT NULL
ALTER TABLE Users
ADD CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ( [GEBRUIKER] ASC, [EL1] ASC, [EL2] ASC, [EL3] ASC )",
TransactionalBehavior.DoNotEnsureTransaction);
var user1 = new User { UserName = "Bassam", Element1 = "1", Element2 = null, Element3 = 3 };
I have :
- Removed all foreign keys which are related to this table
- Dropped the primary key
- Changed the **Column E2 to nullable**
- Adding the modified primary key again
This will causes an error in SQL Server / Oracle DB with the following message in case of SQL Server:
Cannot define PRIMARY KEY constraint on nullable column in table 'Users'.
Think good about it even let say you can do that what will happend with your primary key:
How can you guarantee the uniqueness of your PRIMARY key? Let say your User entity will creates the following row:
Id1 Id2 Id3 , Id4
"a" , "a" , null , null
You cannot create the same entry again because this row will be exists in the table!
Related
I try to add new record :
entity.Id = Id;
_bdc.EquifaxAnswers.Add(entity);
_bdc.SaveChanges();
and Id has exactly defined as primary key and Id in code has value ( unique for table).
And EF create sql code for add record:
INSERT [dbo].[EquifaxAnswers]([FileName], [dtSend], [dtDateTime], [RecordsAll], [RecordsCorrect],
[RecordsIncorrect], [ResendedId], [dtEmailAbout], [StartDate], [EndDate])
VALUES (#0, #1, #2, NULL, NULL, NULL, NULL, NULL, #3, #4)
And as we can see there Id does not exist, so _bdc.SaveChanges();create Exception:
Failed in 25 ms with error: Cannot insert the value NULL into column 'Id', table 'Equifax.dbo.EquifaxAnswers'; column does not allow nulls. INSERT fails.
Primary key definition:
public partial class EquifaxAnswers
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
Why EF don't add Id to INSERT and how to resolve this problem ?
UPD:
Table definition script in database:
CREATE TABLE [dbo].[EquifaxAnswers](
[Id] [int] NOT NULL,
[FileName] [nvarchar](300) NOT NULL,
[dtSend] [datetime] NOT NULL,
[dtDateTime] [datetime] NULL,
[RecordsAll] [int] NULL,
[RecordsCorrect] [int] NULL,
[RecordsIncorrect] [int] NULL,
[ResendedId] [int] NULL,
[dtEmailAbout] [datetime] NULL,
[StartDate] [datetime] NULL,
[EndDate] [datetime] NULL,
CONSTRAINT [PK_EquifaxAnswers] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
You have specified DatabaseGeneratedOption.None
This means that EF is not expecting the database to generate the Id field, and that you should specify the Id field yourself.
If you want the database to generate the Id field automatically, then alter the column to be an IDENTITY type, and change the code to DatabaseGeneratedOption.Identity
Solution:
modelBuilder.Entity<EquifaxAnswers>()
.Property(a => a.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
If this doesn't work - just uninstall and install again all EF packages ( I don't know why - but this is work for me) for all dependent projects , latest stable version of course.
Reasons:
By convention, EF will assume that primary key properties are automatically generated. So we need to say EF that we will do it by our code. However,this is not clear why doesn't work DataAnnotations like this:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
but fluent API is working well. Perhaps the reason is that I use both.
I have a very large CSV file I have to load on a regular basis that contains time series data. Examples of the headers are below:
| SiteName | Company | Date | ResponseTime | Clicks |
This data comes from a service external to the uploader. SiteName and Company are both string fields. In the database these are normalized. There is a Site table and a Company table:
CREATE TABLE [dbo].[Site] (
[Id] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[Name] NVARCHAR(MAX) NOT NULL
)
CREATE TABLE [dbo].[Company] (
[Id] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[Name] NVARCHAR(MAX) NOT NULL
)
As well as the data table.
CREATE TABLE [dbo].[SiteStatistics] (
[Id] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[CompanyId] INT NOT NULL,
[SiteId] INT NOT NULL,
[DataTime] DATETIME NOT NULL,
CONSTRAINT [SiteStatisticsToSite_FK] FOREIGN KEY ([SiteId]) REFERENCES [Site]([Id]),
CONSTRAINT [SiteStatisticsToCompany_FK] FOREIGN KEY ([CompanyId]) REFERENCES [Company]([Id])
)
At around 2 million rows in the CSV file any sort of IO-bound iteration isn't going to work. I need this done in minutes, not days.
My initial thought is that I could pre-load Site and Company into DataTables. I already have the CSV loaded into a datatable in the format that matches the CSV columns. I need to now replace every SiteName with the Id field of Site and every Company with the Id field of Company. What is the quickest, most efficient way to handle this?
If you go with Pre-Loading the Sites and Company's you can get the distinct values using code:
DataView view = new DataView(table);
DataTable distinctCompanyValues = view.ToTable(true, "Company")
DataView view = new DataView(table);
DataTable distinctSiteValues = view.ToTable(true, "Site")
Then load those two DataTables into their SQL Tables using Sql-Bulk-Copy.
Next dump all the data in:
CREATE TABLE [dbo].[SiteStatistics] (
[Id] INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
[CompanyId] INT DEFAULT 0,
[SiteId] INT DEFAULT 0,
[Company] NVARCHAR(MAX) NOT NULL,
[Site] NVARCHAR(MAX) NOT NULL,
[DataTime] DATETIME NOT NULL
)
Then do an UPDATE to set the Referential Integrity fields:
UPDATE [SiteStatistics] ss SET
[CompanyId] = (SELECT Id FROM [Company] c Where ss.[Company] = c.Name),
[SiteId] = (SELECT Id FROM [Site] s Where ss.[Site] = s.Name)
Add the Foreign Key constraints:
ALTER TABLE [SiteStatistics] ADD CONSTRAINT [SiteStatisticsToSite_FK] FOREIGN KEY ([SiteId]) REFERENCES [Site]([Id])
ALTER TABLE [SiteStatistics] ADD CONSTRAINT [SiteStatisticsToCompany_FK] FOREIGN KEY ([CompanyId]) REFERENCES [Company]([Id])
Finally delete the Site & Company name fields from SiteStatistics:
ALTER TABLE [SiteStatistics] DROP COLUMN [Company];
ALTER TABLE [SiteStatistics] DROP COLUMN [Site];
I need some guidance as to why i keep getting this error for my website every time I try to add a product. To let you know I did change the database around a bit, but after I did that i completely recreated the database. I keep getting the following error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.OrderDetails_dbo.Orders_OrderId". The conflict occurred in database "MythData.mdf", table "dbo.Orders", column 'Id'.
the two tables are OrderDetail and Orders.
Order:
CREATE TABLE [dbo].[Orders]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[CustomerId] INT NOT NULL,
[ProductId] INT NOT NULL,
[ShipName] NVARCHAR (MAX) NULL,
[ShipAddress] NVARCHAR (MAX) NULL,
[ShipCity] NVARCHAR (MAX) NULL,
[ShipState] NVARCHAR (MAX) NULL,
[ShipZip] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.Orders] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.Orders_dbo.Customers_CustomerId]
FOREIGN KEY ([CustomerId])
REFERENCES [dbo].[Customers] ([Id]) ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_CustomerId]
ON [dbo].[Orders]([CustomerId] ASC);
OrderDetail table:
CREATE TABLE [dbo].[OrderDetails]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[OrderId] INT NOT NULL,
[ProductId] INT NOT NULL,
[TotalCost] DECIMAL (18, 2) NOT NULL,
[SubTypeMail] BIT NOT NULL,
[Quantity] INT NOT NULL,
CONSTRAINT [PK_dbo.OrderDetails] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.OrderDetails_dbo.Orders_OrderId]
FOREIGN KEY ([OrderId])
REFERENCES [dbo].[Orders] ([Id]) ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_OrderId]
ON [dbo].[OrderDetails]([OrderId] ASC);
Also the class that the error is popping up in :
using (DataContext entities = new DataContext())
{
var orderDetail = entities.OrderDetails.Create();
decimal price = 0;
if (drpSub.SelectedValue == "Mailed")
{
price = 10;
orderDetail.SubTypeMail = true;
}
else
{
price = 5;
orderDetail.SubTypeMail = false;
}
Count = orderDetail.Quantity;
orderDetail.TotalCost = Count * price;
entities.OrderDetails.Add(orderDetail);
entities.SaveChanges(); << this line is the issue!
}
Also including exactly what the trace stated:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.OrderDetails_dbo.Orders_OrderId". The conflict occurred in database "MythData.mdf", table "dbo.Orders", column 'Id'.
Source Error:
Line 121: orderDetail.TotalCost = Count * price;
Line 122: entities.OrderDetails.Add(orderDetail);
Line 123: entities.SaveChanges();
Line 124: while (Count != 0)
Line 125: {
Source File: c:\Users\arielle davenport\Desktop\pets\pets\MythPetsDatabase\MythPetsDatabase\Pages\Products.aspx.cs Line: 123
I know this is long but any help is appreciated. Really stuck right now!
The error message is telling you exactly what the problem is: You're trying to insert a row that has a foreign key constraint to another table, and the value in that column does not exist in the other table.
Let's break it down:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.OrderDetails_dbo.Orders_OrderId".
The conflict occurred in database "MythData.mdf", table "dbo.Orders", column 'Id'.
It gives you the name of the constraint, so you can look at its definition if you need to. But the name pretty much tells you what you need to know... there's a constraint that the OrderId in the OrderDetails table has to match an Id in the Orders table. But the Orders table doesn't currently have an id that matches the one you're trying to insert into the OrderDetails table. It even tells you the problem is in the Orders Table, where the "id" column doesn't have a matching value for the row you're trying to insert into OrderDetails.
There are two potential causes:
1) There is a bug in your code which is trying to insert the wrong value into the id column in the OrderDetails table, or which is just failing to insert a row into the Order table at all
or more likely:
2) You're trying to insert rows in the wrong order... you need to insert the order into the Orders table BEFORE trying to insert the OrderDetails for that order.
You MUST make sure you have inserted the Order before you insert the OrderDetails, so that the critera of the Foreign Key Constaint is satisfied. This is precisely what FK Constraints are for: To prevent you from inserting inconsistent data, where certain values aren't valid (yet).
I need to come up with a solution to have infinite category and subcategories in a database. So this is my idea: creating a table that references parents/child as follows:
As you can see items can be followed down by its id and ParentItemID. However I don't know how I can apply this solution using LINQ.
I have create a model for above table as follow:
class Items
{
public int id { get; set; }
public string ItemName { get; set; }
public int ParentItemID { get; set; }
}
I have loaded list of ‘Items’ form database using EF, and I would like to query the list so it can be grouped and browsed like this:
How can it be done?
Thank in advance for any help.
1) With your model
Add a foreign key (self reference) between parent item id and item id.
CREATE TABLE [dbo].[26957446_All]([id] [int] NOT NULL,[name] [varchar](50) NOT NULL, [parentid] [int] NULL, CONSTRAINT [PK_26957446_All] PRIMARY KEY CLUSTERED ( [id] ASC )
ALTER TABLE [dbo].[26957446_All] WITH CHECK ADD CONSTRAINT [FK_26957446_Circular] FOREIGN KEY([parentid]) REFERENCES [dbo].[26957446_All] ([id])
ALTER TABLE [dbo].[26957446_All] CHECK CONSTRAINT [FK_26957446_Circular]
Generated model: , notice the self reference, names auto generated, All1 are children, All2 is parent reference.
var ents = new DynamicCategory.StackOverflowEntities26957446All();
// all root items loop
foreach (var item in ents.C26957446_All.Where(x => x.C26957446_All2 == null))
{
Console.WriteLine("Id: {0} Name: {1}", item.id, item.name);
PrintChildrenRecursively(item);
}
static int i = 1; //level
static void PrintChildrenRecursively (DynamicCategory.C26957446_All item)
{
foreach (var c in item.C26957446_All1)
{
Console.WriteLine("{2} Child Id: {0} Name: {1}", c.id, c.name, new string('\t', i));
if (c.C26957446_All1.Count > 0)
{
i++;
PrintChildrenRecursively(c);
i--;
}
Console.WriteLine();
}
}
Output:
2) With a different db organization. Separate items and relationships into separate tables. Add foreign keys from Relationship.Child and Relationship.Parent to Items table.
CREATE TABLE [dbo].[26957446_Items]([id] [int] NOT NULL, [name] [varchar](50) NOT NULL, CONSTRAINT [PK_26957446_Items] PRIMARY KEY CLUSTERED ([id] ASC))
CREATE TABLE [dbo].[26957446_Relationships](ParentId] [int] NOT NULL, [ChildId] [int] NOT NULL, CONSTRAINT [PK_Relationships] PRIMARY KEY CLUSTERED ([ParentId] ASC, [ChildId] ASC ))
ALTER TABLE [dbo].[26957446_Relationships] WITH CHECK ADD CONSTRAINT [FK_Child] FOREIGN KEY([ChildId]) REFERENCES [dbo].[26957446_Items] ([id])
ALTER TABLE [dbo].[26957446_Relationships] CHECK CONSTRAINT [FK_Child]
ALTER TABLE [dbo].[26957446_Relationships] WITH CHECK ADD CONSTRAINT [FK_Parent] FOREIGN KEY([ParentId]) REFERENCES [dbo].[26957446_Items] ([id])
ALTER TABLE [dbo].[26957446_Relationships] CHECK CONSTRAINT [FK_Parent]
Generated EF: , notice only class generated with both bottom-up and top-down references. Output is identical, code is very much similar with the exception: item.ItemChildren are children, and root items acces is :
var ents = new DynamicCategory.StackOverflowEntities26957446();
ents.C26957446_Items.Where (x=>x.ItemParents.Count==0)
I am using c# datasets with a MSSQL back end. I have a table that references itself. When I add a parent row then add a child to that, without calling update in between I am getting a constraint exception. I think it is because the inserts are not being performed in the same order the entities were added. Is there any ways around this? I want the user to be able to add items and then commit to the database at the end (when they have confirmed it is all correct).
Here is my table definition and a sample application:
CREATE TABLE [dbo].[AssetServiceItems] (
[ServiceItemID] [int] IDENTITY(1, 1) NOT NULL,
[Description] [nvarchar](50) NOT NULL,
[Parent] [int] NULL,
CONSTRAINT [PK_AssetServiceItems] PRIMARY KEY CLUSTERED ([ServiceItemID] ASC) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON
) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[AssetServiceItems]
WITH CHECK ADD CONSTRAINT [AssetServiceItems_parent] FOREIGN KEY ([Parent]) REFERENCES [dbo].[AssetServiceItems]([ServiceItemID])
ALTER TABLE [dbo].[AssetServiceItems] CHECK CONSTRAINT [AssetServiceItems_parent]
and the program...
public static void Main(string[] args)
{
RelTestTableAdapters.AssetServiceItemsTableAdapter adapter = new RelTestTableAdapters.AssetServiceItemsTableAdapter();
RelTest dataSet = new RelTest();
var parent = dataSet.AssetServiceItems.NewAssetServiceItemsRow();
parent.Description = "Parent";
dataSet.AssetServiceItems.AddAssetServiceItemsRow(parent);
var child = dataSet.AssetServiceItems.NewAssetServiceItemsRow();
child.Description = "child";
child.SetParentRow(parent);
dataSet.AssetServiceItems.AddAssetServiceItemsRow(child);
adapter.Update(dataSet);
Console.ReadKey(true);
}
The INSERT statement conflicted with the FOREIGN KEY SAME TABLE
constraint "AssetServiceItems_parent". The conflict occurred in
database "RelTest", table "dbo.AssetServiceItems", column
'ServiceItemID'.