I have a couple of tables Questions and QuestionQueryParameters I am trying to setup with the entity framework. Essentially I want to see what questions rely on this one and what questions does this question rely on.
As things stand I get an invalid column error "Question_Id1" I am assuming I have not set the foreign key relationships up correctly but I am new to the entity frame work and no amount of "fiddling" has worked yet.
Tables
CREATE TABLE [dbo].[Questions](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Text] [nvarchar](max) NULL,
[Section] [nvarchar](max) NULL,
[Order] [int] NOT NULL,
[Active] [bit] NOT NULL,
[Mandatory] [bit] NOT NULL,
[QuestionType_Id] [int] NULL,
[EntityType_Id] [int] NOT NULL,
[ImportTimestamp] [datetime] NULL,
[ImportUser_Id] [int] NULL,
[Question_Id] [int] NULL,
[DisplayMenuType] [bit] NULL,
[Abbrev] [nvarchar](max) NULL,
[Searchable] [bit] NULL,
CONSTRAINT [PK_Questions] PRIMARY KEY CLUSTERED
(
[Id] ASC,
[EntityType_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]
GO
ALTER TABLE [dbo].[Questions] WITH CHECK ADD CONSTRAINT [FK_Questions_EntityType] FOREIGN KEY([EntityType_Id])
REFERENCES [dbo].[EntityType] ([Id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Questions] CHECK CONSTRAINT [FK_Questions_EntityType]
GO
ALTER TABLE [dbo].[Questions] WITH CHECK ADD CONSTRAINT [FK_Questions_QuestionTypes] FOREIGN KEY([QuestionType_Id])
REFERENCES [dbo].[QuestionTypes] ([Id])
GO
ALTER TABLE [dbo].[Questions] CHECK CONSTRAINT [FK_Questions_QuestionTypes]
GO
ALTER TABLE [dbo].[Questions] WITH CHECK ADD CONSTRAINT [FK_Questions_User] FOREIGN KEY([ImportUser_Id])
REFERENCES [dbo].[Users] ([Id])
GO
ALTER TABLE [dbo].[Questions] CHECK CONSTRAINT [FK_Questions_User]
GO
CREATE TABLE [dbo].[QuestionQueryParameters](
[QuestionQueryParameter_Id] [int] IDENTITY(1,1) NOT NULL,
[Question_Id] [int] NOT NULL,
[EnablingQuestion_Id] [int] NULL,
[EntityType_Id] [int] NOT NULL,
CONSTRAINT [PK__Question__2FBBD18F3E723F9C] PRIMARY KEY CLUSTERED
(
[QuestionQueryParameter_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]
GO
ALTER TABLE [dbo].[QuestionQueryParameters] WITH CHECK ADD CONSTRAINT [FK_QuestQueryParam_Questions] FOREIGN KEY([Question_Id], [EntityType_Id])
REFERENCES [dbo].[Questions] ([Id], [EntityType_Id])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[QuestionQueryParameters] CHECK CONSTRAINT [FK_QuestQueryParam_Questions]
GO
ALTER TABLE [dbo].[QuestionQueryParameters] WITH CHECK ADD CONSTRAINT [FK_QuestQueryParam_QuestionsEnabling] FOREIGN KEY([EnablingQuestion_Id], [EntityType_Id])
REFERENCES [dbo].[Questions] ([Id], [EntityType_Id])
GO
ALTER TABLE [dbo].[QuestionQueryParameters] CHECK CONSTRAINT [FK_QuestQueryParam_QuestionsEnabling]
GO
Classes
public class Question
{
[Key, Column(Order = 0)]
public int Id { get; set; }
public string Text { get; set; }
public string Section { get; set; }
public int Order { get; set; }
public bool Active { get; set; }
public bool Mandatory { get; set; }
public bool Searchable { get; set; }
public virtual QuestionType QuestionType { get; set; }
// public virtual TemplateType TemplateType { get; set; }
public virtual List<QuestionChoice> QuestionChoices { get; set; }
public virtual List<QuestionEnabler> QuestionEnablers { get; set; }
public virtual List<QuestionChoiceQuery> QuestionChoicesQuery { get; set; }
[Key, Column(Order = 1)]
public virtual EntityType EntityType { get; set; }
public DateTime? ImportTimestamp { get; set; }
public int? ImportUser_Id { get; set; }
public virtual List<Question> EnabledQuestions { get; set; }
public virtual List<QuestionQueryParameter> QuestionParameters { get; set; }
public bool DisplayMenuType { get; set; }
public string Abbrev { get; set; }
[InverseProperty("Question")]
public virtual ICollection<QuestionQueryParameter> ReliesOnMe { get; set; }
[InverseProperty("EnablingQuestion")]
public virtual ICollection<QuestionQueryParameter> IRelyOn { get; set; }
}
public class QuestionQueryParameter
{
[Key]
public int QuestionQueryParameter_Id { get; set; }
public virtual Question Question { get; set; }
public virtual Question EnablingQuestion { get; set; }
public virtual EntityType EntityType { get; set; }
}
Entity framework can't tell which foreign key to match up so it makes its own. The solution is InverseProperty which you have, but you need to point to the foreign key, not the navigation property:
[InverseProperty("Question_Id")]
public virtual ICollection<QuestionQueryParameter> ReliesOnMe { get; set; }
[InverseProperty("EnablingQuestion_Id")]
public virtual ICollection<QuestionQueryParameter> IRelyOn { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships
If you want to rename the FK columns in your DB without declaring them in your entity, you should use Fluent API instead Data Annotations to configure those relationships. To change the names you need to use the Map method:
modelBuilder.Entity<QuestionQueryParameter>()
.HasRequired(s => s.Question)
.WithMany(s => s.ReliesOnMe).Map(ca=>ca.MapKey("Question_Id","EntityType_Id")); // Change the FK column names here
modelBuilder.Entity<QuestionQueryParameter>()
.HasRequired(s => s.EnablingQuestion)
.WithMany(s => s.IRelyOn).Map(ca=>ca.MapKey("EnablingQuestion_Id","EntityType_Id")); // Change the FK column names here
Due to you are using a composite PK in the Question entity, the name of the FK columns in the MapKey method must be specified in the same order that the primary keys in the Question entity.
Related
I'm trying to create a tables using Code-First in EF.
I created many versions of my code but I put here only one. It almost works, it means this code creates sql but doesn't work properly.
What I want to get:
I have 2 simple tables : Order and Payer.
Also, I want to create a third table based on foreign keys of these 2.
It wont create it that meet the following rules:
Each Order has exactly one Base Payer. (So I don't need complex key in this case. OrderId can exist only one in this table if record is type of (Base)OrderPayer
Each Order can have 0,1 or many (Extra)OrderPayer. ( So in this case i need put into table complex Key (OrderId + PayerId)
here is my last C# code
public class Order
{
[Key]
public int OrderId { get; set; }
public string OrderName { get; set; }
public virtual BaseOrderPayer BaseOrderPayer { get; set; }
public virtual ICollection<ExtraOrderPayer> ExtraOrderPayers { get; set; }
}
public class Payer
{
[Key]
public int PayerId { get; set; }
public string PayerName { get; set; }
}
public abstract class OrderPayer
{
[Column(Order = 0), Key, ForeignKey("Order")]
public int OrderId { get; set; }
public virtual Order Order { get; set; }
}
public class BaseOrderPayer : OrderPayer
{
[ForeignKey("BasePayer")]
public virtual int? BasePayerId { get; set; }
public virtual Payer BasePayer { get; set; }
}
public class ExtraOrderPayer : OrderPayer
{
[Column(Order = 1), Key, ForeignKey("ExtraPayer")]
public virtual int? ExtraPayerId { get; set; }
public virtual Payer ExtraPayer { get; set; }
}
and SQL that was generated by Update-Database -Script
CREATE TABLE [dbo].[OrderPayers] (
[OrderId] [int] NOT NULL,
[ExtraPayerId] [int],
[BasePayerId] [int],
[Discriminator] [nvarchar](128) NOT NULL,
[Order_OrderId] [int],
CONSTRAINT [PK_dbo.OrderPayers] PRIMARY KEY ([OrderId])
)
CREATE TABLE [dbo].[Payers] (
[PayerId] [int] NOT NULL IDENTITY,
[PayerName] [nvarchar](30),
CONSTRAINT [PK_dbo.Payers] PRIMARY KEY ([PayerId])
)
CREATE TABLE [dbo].[Orders] (
[OrderId] [int] NOT NULL IDENTITY,
[OrderName] [nvarchar](30),
[BaseOrderPayer_OrderId] [int],
CONSTRAINT [PK_dbo.Orders] PRIMARY KEY ([OrderId])
)
CREATE INDEX [IX_OrderId] ON [dbo].[OrderPayers]([OrderId])
CREATE INDEX [IX_ExtraPayerId] ON [dbo].[OrderPayers]([ExtraPayerId])
CREATE INDEX [IX_BasePayerId] ON [dbo].[OrderPayers]([BasePayerId])
CREATE INDEX [IX_Order_OrderId] ON [dbo].[OrderPayers]([Order_OrderId])
CREATE INDEX [IX_BaseOrderPayer_OrderId] ON [dbo].[Orders]([BaseOrderPayer_OrderId])
ALTER TABLE [dbo].[OrderPayers] ADD CONSTRAINT [FK_dbo.OrderPayers_dbo.Payers_BasePayerId] FOREIGN KEY ([BasePayerId]) REFERENCES [dbo].[Payers] ([PayerId])
ALTER TABLE [dbo].[OrderPayers] ADD CONSTRAINT [FK_dbo.OrderPayers_dbo.Payers_ExtraPayerId] FOREIGN KEY ([ExtraPayerId]) REFERENCES [dbo].[Payers] ([PayerId])
ALTER TABLE [dbo].[OrderPayers] ADD CONSTRAINT [FK_dbo.OrderPayers_dbo.Orders_Order_OrderId] FOREIGN KEY ([Order_OrderId]) REFERENCES [dbo].[Orders] ([OrderId])
ALTER TABLE [dbo].[OrderPayers] ADD CONSTRAINT [FK_dbo.OrderPayers_dbo.Orders_OrderId] FOREIGN KEY ([OrderId]) REFERENCES [dbo].[Orders] ([OrderId])
ALTER TABLE [dbo].[Orders] ADD CONSTRAINT [FK_dbo.Orders_dbo.OrderPayers_BaseOrderPayer_OrderId] FOREIGN KEY ([BaseOrderPayer_OrderId]) REFERENCES [dbo].[OrderPayers] ([OrderId])
but his SQL it doesn't even work
I can't insert Order because it need OrderPayer and vice versa :)
Is it possible to fix it according to my expectations ?
p.s.
the tables are very simplified, in fact they contain many other fields
I use in some project EF code First with TPH (in part of classes)
I have class like this:
namespace Billing.Model.Domain.Entities.BilProject
{
[Table("ProjectPriceList")]
public abstract class ProjectPriceList
{
[Key, Column("ProjectId", Order = 0)]
public int ProjectId { get; set; }
[Key, Column("PriceListId", Order = 1)]
public int PriceListId { get; set; }
[Key, Column("PriceListSourceType", Order = 2)]
public int PriceListSourceType { get; set; }
[ForeignKey("PriceListSourceType")]
public virtual BillingProjectCode PriceListSourceTypeCode { get; set; }
public int AddUsrnm { get; set; }
public DateTime AddTmstmp { get; set; }
[ForeignKey("ProjectId")]
public virtual BillingProject BillingProject { get; set; }
public virtual SnapShotPriceList SnapShotPriceList{ get; set; }
}
public class BillingProjectPriceList : ProjectPriceList
{
[ForeignKey("PriceListId")]
public virtual PriceList PriceList { get; set; }
}
public class EstimateProjectPriceList : ProjectPriceList
{
}
}
When I try to generate sql code to create a data base by
Update-Database -Script from console
I receive this SQL as result:
CREATE TABLE [dbo].[ProjectPriceList] (
[ProjectId] [int] NOT NULL,
[PriceListId] [int] NOT NULL,
[PriceListSourceType] [int] NOT NULL,
[AddUsrnm] [int] NOT NULL,
[AddTmstmp] [datetime] NOT NULL,
[Discriminator] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.ProjectPriceList] PRIMARY KEY ([ProjectId], [PriceListId], [PriceListSourceType])
)
CREATE INDEX [IX_ProjectId] ON [dbo].[ProjectPriceList]([ProjectId])
CREATE INDEX [IX_PriceListId] ON [dbo].[ProjectPriceList]([PriceListId])
CREATE INDEX [IX_PriceListSourceType] ON [dbo].[ProjectPriceList]([PriceListSourceType])
ALTER TABLE [dbo].[ProjectPriceList] ADD CONSTRAINT [FK_dbo.ProjectPriceList_dbo.BillingProject_ProjectId] FOREIGN KEY ([ProjectId]) REFERENCES [dbo].[BillingProject] ([ProjectId]) ON DELETE CASCADE
ALTER TABLE [dbo].[ProjectPriceList] ADD CONSTRAINT [FK_dbo.ProjectPriceList_dbo.BillingProjectCode_PriceListSourceType] FOREIGN KEY ([PriceListSourceType]) REFERENCES [dbo].[BillingProjectCode] ([CodeId]) ON DELETE CASCADE
ALTER TABLE [dbo].[ProjectPriceList] ADD CONSTRAINT [FK_dbo.ProjectPriceList_dbo.PriceList_PriceListId] FOREIGN KEY ([PriceListId]) REFERENCES [dbo].[PriceList] ([PriceListId]) ON DELETE CASCADE
The last FK Constraint is redudant and make me trouble if i try add new EstimateProjectPriceList.
My question is
How to stop create this FK by some code Data Annotations or Fluent Api in OnModelCreating ?
Thnx for any help..
I would like to create many-to-many relation with .NET MVC EF. I have Client model (it could be employer or employee or colleague etc., company or person). So any of the client can have employees or employer. I am not sure how to set this relation in EF.
My models (parts of db context):
public partial class Client
{
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ClientRelation> TargetClientRelations { get; set; }
public virtual ICollection<ClientRelation> SourceClientRelations { get; set; }
}
public enum ClientRelationType
{
Employer_Employee
}
public class ClientRelation
{
public long Id { get; set; }
public virtual Client Client { get; set; }
public virtual Client TargetClient { get; set; }
public ClientRelationType ClientRelationType { get; set; }
}
The problem is EF creates this relation table. I gues I should create some mapping..
CREATE TABLE [dbo].[ClientRelations](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Client_Id] [bigint] NULL,
[TargetClient_Id] [bigint] NULL,
[Client_Id1] [bigint] NULL,
[Client_Id2] [bigint] NULL,
[ClientRelationType] [int] NOT NULL,
CONSTRAINT [PK_dbo.ClientRelations] 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]
GO
ALTER TABLE [dbo].[ClientRelations] ADD DEFAULT ((0)) FOR [ClientRelationType]
GO
ALTER TABLE [dbo].[ClientRelations] WITH CHECK ADD CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id] FOREIGN KEY([Client_Id])
REFERENCES [dbo].[Clients] ([Id])
GO
ALTER TABLE [dbo].[ClientRelations] CHECK CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id]
GO
ALTER TABLE [dbo].[ClientRelations] WITH CHECK ADD CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id1] FOREIGN KEY([Client_Id1])
REFERENCES [dbo].[Clients] ([Id])
GO
ALTER TABLE [dbo].[ClientRelations] CHECK CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id1]
GO
ALTER TABLE [dbo].[ClientRelations] WITH CHECK ADD CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id2] FOREIGN KEY([Client_Id2])
REFERENCES [dbo].[Clients] ([Id])
GO
ALTER TABLE [dbo].[ClientRelations] CHECK CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_Client_Id2]
GO
ALTER TABLE [dbo].[ClientRelations] WITH CHECK ADD CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_TargetClient_Id] FOREIGN KEY([TargetClient_Id])
REFERENCES [dbo].[Clients] ([Id])
GO
ALTER TABLE [dbo].[ClientRelations] CHECK CONSTRAINT [FK_dbo.ClientRelations_dbo.Clients_TargetClient_Id]
GO
You need to add some additional configuration to your model to specify which property is related with.
Using Data Anotations you will need to use InverseProperty attribute:
public class ClientRelation
{
public long Id { get; set; }
[InverseProperty("SourceClientRelations")]
public virtual Client Client { get; set; }
[InverseProperty("TargetClientRelations")]
public virtual Client TargetClient { get; set; }
public ClientRelationType ClientRelationType { get; set; }
}
If you decide go for Fluent Api then your configurations would be:
modelBuilder.Entity<ClientRelation>()
.HasOptional(l => l.TargetClient)
.WithMany(p => p.TargetClientRelations);
modelBuilder.Entity< ClientRelation>()
.HasOptional(l => l.Client)
.WithMany(p => p.SourceClientRelations);
This is my trial project using breeze/angular/EF. I don't understand why I get this error because I thought I had the same structure working before.
public class TshirtOrder
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
public int Id { get; set; }
[ForeignKey("Type")]
public int TshirtTypeId { get; set; }
public virtual TshirtType Type { get; set; }
[ForeignKey("Size")]
public int TshirtSizeId { get; set; }
public virtual TshirtSize Size { get; set; }
public double UnitPrice { get; set; }
public int Quantity { get; set; }
[ForeignKey("TshirtOrder")]
public int TshirtOrderId { get; set; }
public TshirtOrder TshirtOrder { get; set; }
}
The table definition looks like this:
CREATE TABLE [dbo].[TshirtOrder] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_dbo.TshirtOrder] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[OrderItem] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[TshirtTypeId] INT NOT NULL,
[TshirtSizeId] INT NOT NULL,
[UnitPrice] FLOAT (53) NOT NULL,
[Quantity] INT NOT NULL,
[TshirtOrderId] INT NOT NULL,
CONSTRAINT [PK_dbo.OrderItem] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.OrderItem_dbo.TshirtType_TshirtTypeId] FOREIGN KEY ([TshirtTypeId]) REFERENCES [dbo].[TshirtType] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.OrderItem_dbo.TshirtSize_TshirtSizeId] FOREIGN KEY ([TshirtSizeId]) REFERENCES [dbo].[TshirtSize] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.OrderItem_dbo.TshirtOrder_TshirtOrderId] FOREIGN KEY ([TshirtOrderId]) REFERENCES [dbo].[TshirtOrder] ([Id]) ON DELETE CASCADE
);
This is how it gets saved in Breeze datacontext:
function _createTshirtOrder() {
var order = manager.createEntity("TshirtOrder");
order.orderItems.push(createOrderItem(lookups.tshirtTypes[0], lookups.tshirtSizes[0], 10));
common.saveEntity(order);
return order;
function createOrderItem(type, size, unitPrice) {
var item = manager.createEntity("OrderItem");
item.type = type;
item.size = size;
item.unitPrice = unitPrice;
item.quantity = 0;
return item;
}
}
Here is the exact error:
{"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_dbo.OrderItem_dbo.TshirtOrder_TshirtOrderId\". The conflict occurred in database \"dbbb\", table \"dbo.TshirtOrder\", column 'Id'.\r\nThe statement has been terminated."}
So, where is the problem?
I don't know what your "saveEntity" method looks like but I'm guessing it calls
entityManager.saveChanges([order]);
If so, then the problem is that you are only saving the order and NOT the orderItem as well, because you told it to only save the one order. Breeze tracks any changes to the entityManager so a better solution is usually to just let Breeze figure it out for you. i.e.
entityManager.saveChanges(); or entityManager.saveChanges(null, ... );
Which will save all added, modified or deleted records in the entityManager.
Alternately you can specify all of the entities you want saved.
entityManager.saveChanges([order, orderItem1, orderItem2, ... ]);
I'm using EF 5.0 (CodeFirst) with VS 2012 and am having trouble making a query using SqlQuery. The problem happens in the mapping between the property name of the entity and the name of the column in the database.
My entity (model):
[Table("Teste")]
public class TesteEntity
{
[Column("Teste_Id")]
public int Id { get; set; }
[Required]
public bool IsAdministrator { get; set; }
[Required]
public string Name { get; set; }
}
When I run the query, I get an error.
Rotine:
List<TesteEntity> list = dataContext.Database.SqlQuery<TesteEntity>("SELECT * FROM Teste").ToList();
Error:
The data reader is incompatible with the specified '....TesteEntity'. A member of the type, 'Id', does not have a corresponding column in the data reader with the same name.
Table structure in database:
CREATE TABLE [dbo].[Teste]( [Id] [int] IDENTITY(1,1) NOT NULL,
[IsAdministrator] [bit] NOT NULL, [Name] [nvarchar](max) COLLATE
Latin1_General_CI_AS NOT NULL, CONSTRAINT [PK_dbo.Teste] PRIMARY KEY
CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF)
ON [PRIMARY] ) ON [PRIMARY]
Obviously when I take DataAnnotation [Column ("Teste_Id")] and recreate the table, everything works, but wanted to know if you have to do this query using DataAnnotation [Column ("Teste_Id")].
Thanks
Please, write this code as follow:
[Table("Teste")]
public class TesteEntity
{
[Column("TesteId")]
[Key]
public int Id { get; set; }
[Required]
public bool IsAdministrator { get; set; }
[Required]
public string Name { get; set; }
}
I suggest you to write your code How EF CF work fine. For your code it is as follow:
public class Teste
{
public int TesteId{ get; set; }
[Required]
public bool IsAdministrator { get; set; }
[Required]
public string Name { get; set; }
}