.Net Core EF doesn't allow me to enter same Foreign Key - asp.net-core

I have got a Model with Foreign Key. Some how .NET Core EF doesn't let me enter the same Foreign key twice to the table.
public class DolsMcaClientModel
{
[Key]
public int DolsMcaClientID { get; set; }
public int DolsMcaItemID { get; set; }
public virtual DolsMcaItemModel DolsMcaItemModel { get; set; }
public int ClientID { get; set; }
[Required]
public int FileID { get; set; }
public virtual FileModel FileModel { get; set; }
}
In this table DolsMcaClientID is my Identity Column and DolsMcaItemID is my Foreign column. DolsMcaItemModel is my navigation property.
I can't enter the same DolsMcaItemID for different client.
DolsMcaItemID acting like a primary key in the table. But it is not.
ERROR: System.Data.SqlClient.SqlException: Cannot insert duplicate key row in object 'dbo.DolsMcaClientModels' with unique index 'IX_DolsMcaClientModels_DolsMcaItemID'. The duplicate key value is (1).
If I delete DolsMcaItemID 1 item from the table, then i can add new entry to the table with DolsMcaItemId 1, but only once with any clientID... i can't enter DolsMcaItem 1 for with any other clientID
My SQL Table create query is:
CREATE TABLE [dbo].[DolsMcaClientModels](
[DolsMcaClientID] [int] IDENTITY(1,1) NOT NULL,
[DolsMcaItemID] [int] NOT NULL,
[ClientID] [int] NOT NULL,
[FileID] [int] NOT NULL,
CONSTRAINT [PK_DolsMcaClientModels] PRIMARY KEY CLUSTERED
(
[DolsMcaClientID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[DolsMcaClientModels] WITH CHECK ADD CONSTRAINT [FK_DolsMcaClientModels_DolsMcaItemModels_DolsMcaItemID] FOREIGN KEY([DolsMcaItemID])
REFERENCES [dbo].[DolsMcaItemModels] ([DolsMcaItemID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[DolsMcaClientModels] CHECK CONSTRAINT [FK_DolsMcaClientModels_DolsMcaItemModels_DolsMcaItemID]
GO
ALTER TABLE [dbo].[DolsMcaClientModels] WITH CHECK ADD CONSTRAINT [FK_DolsMcaClientModels_FileModels_FileID] FOREIGN KEY([FileID])
REFERENCES [dbo].[FileModels] ([FileID])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[DolsMcaClientModels] CHECK CONSTRAINT [FK_DolsMcaClientModels_FileModels_FileID]
GO

The UNIQUE index [IX_DolsMcaClientModels_DolsMcaItemID] on that column is preventing you from committing another record with the same [DolsMcaItemID].
Fix is to drop the unique index:
ALTER TABLE [dbo].[DolsMcaClientModels] DROP INDEX [IX_DolsMcaClientModels_DolsMcaItemID];
CREATE INDEX [IX_DolsMcaClientModels_DolsMcaItemID] ON [dbo].[DolsMcaClientModels] ([DolsMcaItemID])
Don't forget to scaffold your db context to remove the constraint from code.

Related

Model's indexes doesn't validate

Table in postgres:
CREATE TABLE "public"."filters" (
"Id" int4 NOT NULL DEFAULT nextval('"filters_Id_seq"'::regclass),
"Name" varchar(200) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying,
"Type" int4 NOT NULL,
"Alias" varchar(200) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying
)
;
-- ----------------------------
-- Indexes structure for table filters
-- ----------------------------
CREATE UNIQUE INDEX "filters_unique_alias_key" ON "public"."filters" USING btree (
"Alias" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
CREATE UNIQUE INDEX "filters_unique_name_key" ON "public"."filters" USING btree (
"Name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
);
-- ----------------------------
-- Primary Key structure for table filters
-- ----------------------------
ALTER TABLE "public"."filters" ADD CONSTRAINT "filters_primary_key" PRIMARY KEY ("Id");
Model:
[Table("filters")]
public class Filter
{
[Key] public int Id { get; set; }
[Required]
[StringLength(200)]
public string Name { get; set; }
[Required]
[StringLength(200)]
public string Alias { get; set; }
[Required] public FilterType Type { get; set; }
}
public enum FilterType
{
Logic = 0,
Text = 1,
Number = 2
}
Context:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Filter>().HasIndex(model => model.Name).HasName("filters_unique_name_key").IsUnique();
builder.Entity<Filter>().HasIndex(model => model.Alias).HasName("filters_unique_alias_key").IsUnique();
}
I'm making post request with NOT unique values and receive DbUpdateException from postgres:
public IActionResult Create(Filter filter = null)
{
if (ModelState.IsValid && filter != null)
{
// code
}
}
Why if I defined indexes by the fluent api a modelstate is valid but index validation isn't working? Seems ef core ignore indexes validation but why? How to validate it?
The unique index fluent API config doesn't affect model validation. It can't know whether a particular posted value is unique or not without querying the database, which is not something the modelbinder is empowered to do or even should do. If you want to add validation for this, you'll need to do so manually.
var filter = await _context.Filters.FirstOrDefaultAsync(x => x.Name == model.Name || x.Alias == model.Alias);
if (filter?.Name == model.Name)
ModelState.AddModelError(nameof(model.Name), "Name must be unique.");
if (filter?.Alias == model.Alias)
ModelState.AddModelError(nameof(model.Alias), "Alias must be unique.");

write SQL Query in the ASP.Net MVC Model class

I have this database code. I am using Asp.net MVC Code first method. so, how can I implement in my model?
CREATE TABLE [dbo].[security_code_mapping_intmdt]
(
[SOURCE_SECURITY_CODE] [VARCHAR](25) NOT NULL,
[SECURITY_CODE] [VARCHAR](25) NOT NULL,
[INSTRUMENT_NAME] [VARCHAR](15) NOT NULL,
[SRC_FLAG] [VARCHAR](10) NULL,
CONSTRAINT [PK_COMMAP_HSBC_CODE]
PRIMARY KEY CLUSTERED ([SOURCE_SECURITY_CODE] ASC)
)
GO
my question is about what should I written in my model class for making with the database with code first approches.
You can try like this.
public class security_code_mapping_intmdt
{
[Key]
[StringLength(25)]
[Required]
public string SOURCE_SECURITY_CODE{get;set;}
[StringLength(25)]
[Required]
public string SECURITY_CODE{get;set;}
[StringLength(15)]
[Required]
public string INSTRUMENT_NAME{get;set;}
[StringLength(10)]
[Required]
public string SRC_FLAG{get;set;}
}

invalid Column name Practice_PK

I have the below code where am working on an ASp.net MVC application
public class Element
{
/// <summary>
/// Primary Key
/// </summary>
[Key]
public int Pk { get; set; }
[ForeignKey("Practice_PK")]
[Display(Name = "Practices")]
public Practice Practice { get; set; }
[Display(Name = "Practices")]
public int Practice_PK { get; set; }
}
Database
CREATE TABLE [dbo].[Elements] (
[Pk] INT IDENTITY (1, 1) NOT NULL,
[Practice_PK] INT NULL,
CONSTRAINT [FK_dbo.Elements_dbo.Practices_Practice_PK] FOREIGN KEY ([Practice_PK]) REFERENCES [dbo].[Practices] ([PK]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_Practice_PK]
ON [dbo].[Elements]([Practice_PK] ASC);
I am getting the Error "Invalid Column name Practice_PK" everytime i try to create, Edit a page. I know this has been addressed many times but the error itself is so ambiguous i dont know how to resolve.
I just resolved my issue .Basically the 'Practice_PK' returning the error was for another variable ElementType (Not included the code above ) that is of the type ElementType that should have had a Practice_PK varaible but did not

Fluent NHibernate one-to-one with bidirectional HasOne not saving child

I'm having a problem getting a one-to-one relationship working with fluent nhibernate. I've read a multitude of posts on this and it seems like the preferred approach is the shared primary key method, where the parent and child have the same primary key value and child PK is also FK to parent.
The parent and child classes each have a reference to the other (bi-directional HasOne) and the child is configured to get it's key value from the parent.
I believe I have it setup correctly, but when I create a new Parent, attach a new Child and then try to save it, the parent saves correctly and the key value is updated on the child object, but the child is not actually saved to the DB.
Here are the classes and maps:
public class Parent
{
public virtual int ParentID { get; set; }
public virtual string Name { get; set; }
public virtual Child Child { get; set; }
public virtual void Add(Child child)
{
child.Parent = this;
Child = child;
}
}
public class Child
{
public virtual int ParentID { get; set; }
public virtual string Name { get; set; }
public virtual Parent Parent { get; set; }
}
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
Id(x => x.ParentID).GeneratedBy.Identity();
Map(x => x.Name);
HasOne(x => x.Child).Cascade.All();
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
Id(x => x.ParentID).GeneratedBy.Foreign("Parent");
Map(x => x.Name);
HasOne(x => x.Parent).Constrained().ForeignKey();
}
}
Here is the schema that NHibernate creates (removed some GOs for brevity):
CREATE TABLE [dbo].[Parent](
[ParentID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](255) NULL,
PRIMARY KEY CLUSTERED
(
[ParentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [dbo].[Child](
[ParentID] [int] NOT NULL,
[Name] [nvarchar](255) NULL,
PRIMARY KEY CLUSTERED
(
[ParentID] 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].[Child] WITH CHECK ADD CONSTRAINT [FK_ChildToParent] FOREIGN KEY([ParentID])
REFERENCES [dbo].[Parent] ([ParentID])
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_ChildToParent]
So it seems to create the schema I expected. But I just can't get the child to save:
var parent = new Parent() { Name = "Parent_1" };
parent.Add(new Child { Name = "Child_1" });
session.Save(parent);
As mentioned, this will save the parent correctly and update the ParentID property on the Child object with the value from the parent, but the Child is not actually saved to the DB and no error is generated.
Any idea what I'm doing wrong?
Never mind. I feel stupid. The mappings are correct, but you have to wrap the Save in a transaction for the child object to be persisted, which I wasn't doing in my test app. Once I added the transaction it worked as expected.

Have an Entity Framework field reference one of several derived tables via a discriminator (Using TPT)

I'm trying to find a way to create this relationship from Entity Framework 5's Code First.
In the example below, I have some Stock which can either belong to a Warehouse or a Row.
Stock Table
'Id', 'SerialNo', 'Discriminator', 'LocationId'
345, ABC123, Warehouse, 4
123, ABC124, Row, 12
Warehouse Table
'Id', 'Name'
4, WH-One
8, WH-Two
Row Table
'Id', 'Name'
6, RowA
12, RowB
The Discriminator column on the table Stock determines which of the related tables the LocationId is referring to. For example:
Stock with Id '345' has a reference to row with Id: 4 (WH-One) on the Warehouse table
Can this type of relationship be mapped with EF Code First? It's certainly no trouble to query against this structure in SQL Server.
SELECT Stock.SerialNo, COALESCE(Warehouse.Name, Row.Name) AS Name
FROM Stock
LEFT OUTER JOIN Warehouse ON Stock.Id = Warehouse.Id AND Stock.Discriminator = 'Warehouse'
LEFT OUTER JOIN Row ON Stock.Id = Row.Id AND Stock.Discriminator = 'Row'
Which should return:
SerialNo, Name
ABC123, WH-One
ABC124, RowB
Ideally, I'd like to have either an interface or abstract base class which Warehouse and Row and derive from. And a navigation property called Location that would refer to either table cast to the abstract/interface.
Alternatively, I'd like to know if anyone has a better suggestion to describe a relationship in EF Code First that allows one entity to reference one of several other similar entities.
It's Code First so I would do this:
First - create the classes I want in code:
public abstract class Location
{
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Stock> StockItems { get; set; }
}
public class Warehouse : Location
{
public int NumberOfLoadingDocks { get; set; }
}
public class Row : Location
{
public int NumberOfShelves { get; set; }
}
public class Stock
{
public int ID { get; set; }
public string SerialNo { get; set; }
public int LocationID { get; set; }
}
Then add them to the context:
public partial class MyContext : DbContext
{
public DbSet<Location> Locations { get; set; }
public DbSet<Warehouse> Warehouses { get; set; }
public DbSet<Row> Rows { get; set; }
public DbSet<Stock> Stocks { get; set; }
}
Then in Package-Manager console:
Add-Migration "Locations"
Update-Database -Script
That lets me see the tables Entity Framework would create:
CREATE TABLE [dbo].[Stocks] (
[ID] [int] NOT NULL IDENTITY,
[SerialNo] [nvarchar](max),
[LocationID] [int] NOT NULL,
CONSTRAINT [PK_dbo.Stocks] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_LocationID] ON [dbo].[Stocks]([LocationID])
CREATE TABLE [dbo].[Locations] (
[ID] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
[NumberOfShelves] [int],
[NumberOfLoadingDocks] [int],
[Discriminator] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.Locations] PRIMARY KEY ([ID])
)
ALTER TABLE [dbo].[Stocks] ADD CONSTRAINT [FK_dbo.Stocks_dbo.Locations_LocationID] FOREIGN KEY ([LocationID]) REFERENCES [dbo].[Locations] ([ID])
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'201309120832257_Locations'....
Not the same tables that you have. This is Table-per-Hierarchy inheritance. If you are not happy with that then you need to look at Table Per Type inheritance
EDIT
To get TPT inheritance you can add the Table attribute to the inherited classes like this:
[System.ComponentModel.DataAnnotations.Schema.Table("Warehouses")]
public class Warehouse : Location
{
public int NumberOfLoadingDocks { get; set; }
}
[System.ComponentModel.DataAnnotations.Schema.Table("Rows")]
public class Row : Location
{
public int NumberOfShelves { get; set; }
}
And now you get separate tables for each type:
CREATE TABLE [dbo].[Locations] (
[ID] [int] NOT NULL IDENTITY,
[Name] [nvarchar](max),
CONSTRAINT [PK_dbo.Locations] PRIMARY KEY ([ID])
)
CREATE TABLE [dbo].[Rows] (
[ID] [int] NOT NULL,
[NumberOfShelves] [int] NOT NULL,
CONSTRAINT [PK_dbo.Rows] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_ID] ON [dbo].[Rows]([ID])
CREATE TABLE [dbo].[Warehouses] (
[ID] [int] NOT NULL,
[NumberOfLoadingDocks] [int] NOT NULL,
CONSTRAINT [PK_dbo.Warehouses] PRIMARY KEY ([ID])
)
CREATE INDEX [IX_ID] ON [dbo].[Warehouses]([ID])
ALTER TABLE [dbo].[Stocks] ADD CONSTRAINT [FK_dbo.Stocks_dbo.Locations_LocationID] FOREIGN KEY ([LocationID]) REFERENCES [dbo].[Locations] ([ID])
ALTER TABLE [dbo].[Rows] ADD CONSTRAINT [FK_dbo.Rows_dbo.Locations_ID] FOREIGN KEY ([ID]) REFERENCES [dbo].[Locations] ([ID])
ALTER TABLE [dbo].[Warehouses] ADD CONSTRAINT [FK_dbo.Warehouses_dbo.Locations_ID] FOREIGN KEY ([ID]) REFERENCES [dbo].[Locations] ([ID])
And if you are not happy with that you should look at Table Per Concrete Type Inheritance...