EntityFramework SqlQuery does not work with custom mapping (DataAnnotation Column) - entity-framework

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; }
}

Related

Entity Framework Core 6 is auto incrementing non-key columns

Entity Framework Core 6 is auto-incrementing columns in my table that it shouldn't be.
I have a table in SQL Server defined like this:
CREATE TABLE [dbo].[Company]
(
[Company_ID] [int] IDENTITY(1,1) NOT NULL,
[CompanyName] [varchar](100) NOT NULL,
[CreatedOnUtc] [datetime] NOT NULL,
[AccountManager_ID] [int] NULL,
[Project_ID] [int] NOT NULL,
[Customer_ID] [int] NOT NULL
CONSTRAINT [PK_Company]
PRIMARY KEY CLUSTERED ([Company_ID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Company]
ADD CONSTRAINT [DF_Company_CreatedOnUtc] DEFAULT (GETUTCDATE()) FOR [CreatedOnUtc]
GO
My entity is defined like this - I am explicitly defining the key column and that it's an identity.
[Table("Company")]
public partial class CompanyEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Required]
[DisplayName("Company ID")]
public int Company_ID { get; set; }
[Required]
[MaxLength(100)]
[DisplayName("Company Name")]
public string CompanyName { get; set; } = "";
[ForeignKey("AccountManager")]
[DisplayName("Account Manager ID")]
public int? AccountManager_ID { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[Required]
[DisplayName("Created On Utc")]
public DateTime CreatedOnUtc { get; set; }
[ForeignKey("Project")]
//[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Required]
[DisplayName("Project ID")]
public int Project_ID { get; set; }
[ForeignKey("Customer")]
[Required]
[DisplayName("Customer ID")]
//[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Customer_ID { get; set; }
public AccountManagerEntity? AccountManager { get; set; }
public CustomerEntity Customer { get; set; } = new CustomerEntity();
public ProjectEntity Project { get; set; } = new ProjectEntity();
}
When I create and save a new CompanyEntity record
var company = new CompanyEntity()
{
CompanyName = "Test",
AccountManager_ID = 1
Project_ID = 1,
Customer_ID = 1,
};
Context.Company.Add(company);
await Context.SaveChangesAsync();
What I'd expect to see happen is a new record is added to the Company table that looks like:
Company_ID: xxx (auto-incremented in DB)
CompanyName: Test
AccountManager_ID: 1
Project_ID: 1
Customer_ID: 1
CreatedOnUtc: xx/xx/xxxx (auto generated)
Instead, what I see happening is that both the Project_ID and Customer_ID columns are being automatically incremented. So I'm ending up with records like this:
Company_ID: 1
CompanyName: Test
AccountManager_ID: 1
Project_ID: 1
Customer_ID: 1
CreatedOnUtc: 3/27/2022 18:13:00
Then if I delete this record and run my code again, I end up with another record (which I'd expect), but Project_ID and Customer_ID have incremented instead of using my values:
Company_ID: 2
CompanyName: Test
AccountManager_ID: 1
Project_ID: 2
Customer_ID: 2
CreatedOnUtc: 3/27/2022 18:13:00
I can see in the SQL Server profiler that EF is passing the incremented values. I'm sure this is because of some convention, but I have explicitly set attributes on these columns. AccountManager_ID seems to work OK - the only difference with that one is it's not a required field. I also tried adding
[DatabaseGenerated(DatabaseGeneratedOption.None)]
to Project_ID / Customer_ID, but that did not make any difference.
How do I tell EF, "don't do that"?
EDIT: OK, I figured out why this was happening. Because I'm creating an instance of both the CustomerEntity and ProjectEntity as default values, it's assuming I am also creating new records in these other tables. Removing the = new *Entity(); portion fixed the issue. I had only added these to make the compiler warning about the non-nullable property having a value when it exits the constructor go away. Oops.
public CustomerEntity Customer { get; set; } = new CustomerEntity();
public ProjectEntity Project { get; set; } = new ProjectEntity();
This code automatically creates new instances of Customer and Project and assignes new keys
public CustomerEntity Customer { get; set; } = new CustomerEntity();
public ProjectEntity Project { get; set; } = new ProjectEntity();
leave just like this
public CustomerEntity Customer { get; set; }
public ProjectEntity Project { get; set; }

How to block creation redundant FK Constraint in EF TPH Code First

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..

Entity Framework 5 CodeFirst - "Column names in each table must be unique."

I'm creating the following table on PostgreSQL:
create table dbo.user_ratings (
user_id int not null,
user_rated_id int not null,
value decimal not null,
status_id int not null,
created_at timestamp with time zone not null,
updated_at timestamp with time zone null,
user_comment text null,
primary key (user_id, user_rated_id),
foreign key (user_id) references dbo.users(id),
foreign key (status_id) references dbo.status(id),
foreign key (user_rated_id) references dbo.users(id));
When mapping the table using CodeFirst, I'm doing the following:
[Table("user_ratings", Schema="dbo")]
public class UserRating {
[Key, Column("user_id", Order = 0)]
public int UserId { get; set; }
public virtual User User { get; set; }
[Key, Column("user_rated_id", Order = 1)]
public int UserRatedId { get; set; }
public virtual User UserRated { get; set; }
[Column("status_id")]
public int StatusId { get; set; }
public virtual Status Status { get; set; }
public decimal Value { get; set; }
[Column("user_comment")]
public string UserComment { get; set; }
[Column("created_at")]
public DateTime CreatedAt { get; set; }
[Column("updated_at")]
public DateTime UpdatedAt { get; set; }
}
Well, so far, so good. When I try to query something, I'm getting the error below:
Column names in each table must be unique. Column name 'User_Id' in table 'user_ratings' is specified more than once.
What is wrong with this? When I remove the mapping related to the column user_id, it's passing, but it's not right. Can someone help me?
Thank you all!!!
Seems that this error is related only to SQLServer databases. I still had some SQLServer configurations on my Web.config/App.config, that's why this error was appearing. Without SQLServer configurations, the error is gone.

Entity framework code first cant create primary and foreign key relationship

I am trying to create a relationship between two tables but keep getting the following error:
The ForeignKeyAttribute on property 'CallLogId' on type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity' is not
valid. The navigation property 'ApiCallLog' was not found on the
dependent type
'Ylp.Web.ParkingApi.DataLayer.Entities.ApiCallLogDetailEntity'. The
Name value should be a valid navigation property name.
DbContextMapping:
modelBuilder.Entity<ApiCallLogDetailEntity>()
.HasRequired<ApiCallLogEntity>(p => p.ApiCallLog);
Primary table:
[Table("ApiCallLog")]
public class ApiCallLogEntity
{
[Key, Column(Order = 0)]
public string CallLogId { get; set; }
[Key, Column(Order = 1)]
public string UserId { get; set; }
[Required]
public string CallFilterId { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
[Required]
public int Count { get; set; }
public virtual ICollection<ApiCallLogDetailEntity> Details { get; set; }
}
foreign table:
[Table("ApiCallLogDetail")]
public class ApiCallLogDetailEntity
{
[ForeignKey("ApiCallLog")]
public string CallLogId { get; set; }
[Required]
public string PrametersHashCode { get; set; }
[Required]
public DateTime LastUpdated { get; set; }
public ApiCallLogEntity ApiCallLog { get;}
}
The foreign key must refer to the whole primary key of the parent table. In your parent table you have a composite primary key which includes CallLogId and UserId. The message is confusing, but this can be part of the error. Is it really necessary to include the UserId in the PK?
Another error is that you have not defined the PK in the dependent table. If the UserId is also necessary on the PK, include it in the dependent table, and make it part of the FK.

Linking two tables in EntityFramework CodeFirst models

I am trying to learn asp.net MVC, by converting a web forms app I have. It's a room booking app, where there is a customer table (tblCustomerBooking) which has a one to many relationship with tblRental - so one customer can book more than one room. The fields that match each other are tblCustomerBooking.customer_id -> tblRental.customer_ref
I'm trying to use code first - and building a model class - but I can't figure out how to link the two tables, so that when I query the dbContext, it will return a customer, with one or more rentals within the same model.
My table definitions are:
CREATE TABLE [dbo].[tblCustomerBooking](
[customer_id] [bigint] IDENTITY(1,1) NOT NULL,
[room_id] [bigint] NULL,
[customer_name] [varchar](110) NULL,
[customer_email] [varchar](50) NULL
CONSTRAINT [PK_tblCustomerBooking] PRIMARY KEY CLUSTERED
(
[customer_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] TEXTIMAGE_ON [PRIMARY]
CREATE TABLE [dbo].[tblRental](
[rental_id] [bigint] IDENTITY(1,1) NOT NULL,
[room_id] [bigint] NOT NULL,
[check_in] [datetime] NOT NULL,
[check_out] [datetime] NOT NULL,
[customer_ref] [bigint] NULL,
[room_cost] [decimal](18, 2) NULL
CONSTRAINT [PK_tblRental_1] PRIMARY KEY CLUSTERED
([rental_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] TEXTIMAGE_ON [PRIMARY]
My attempt at building the model for this is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Data.Entity;
namespace MvcApplication23.Models
{
public class tblRental
{
[Key()]
public int rental_id { get; set; }
public int room_id { get; set; }
public DateTime check_in { get; set; }
public DateTime check_out { get; set; }
public long customer_ref { get; set; }
[ForeignKey("customer_ref")]
public tblCustomerBooking Customer {get;set;}
public decimal room_cost { get; set; }
}
public class tblCustomerBooking
{
[Key()]
public long customer_id { get; set; }
public string customer_name { get; set; }
public string customer_email { get; set; }
public ICollection<tblRental> Rentals {get;set;}
}
public class RentalContext : DbContext
{
public DbSet<tblCustomerBooking> customers { get; set; }
public DbSet<tblRental> rentals { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Web.Http;
using MvcApplication23.Models;
namespace MvcApplication23.api.Controllers
{
public class RentalController : ApiController
{
private RentalContext db = new RentalContext();
// GET /api/rental/5
public IQueryable<tblCustomerBooking> Get(int id)
{
return db.customers.Include("rentals").FirstOrDefault(c=>c.customer_id==id);
}
** I've updated the info above, with the actual table names that already existed in the database **
How to I link the two tables in the model? And then given a customer_id, how would I query the DbContext to return a customer, with any related entries in the tblRental table?
Thank you very much for any pointers,
Mark
To link two entities, provide a navigation property:
public class Rental
{
[Key]
public int rental_id { get; set; }
public int room_id { get; set; }
public DateTime check_in { get; set; }
public DateTime check_out { get; set; }
public int customer_ref { get; set; }
[ForeignKey("customer_ref")]
public virtual Customer Customer {get;set;}
public decimal room_cost { get; set; }
}
public class Customer
{
[Key]
public int customer_id { get; set; }
public string customer_name { get; set; }
public string customer_email { get; set; }
public virtual ICollection<Rental> Rentals {get;set;}
}
And to query your customer :
return this.DataContext.customers.Include("Rentals").FirstOrDefaul(c=>c.customer_id==customerId);
using System.ComponentModel.DataAnnotations.Schema;
public class Rental
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual int id { get; set; }
public virtual int room_id { get; set; }
public virtual DateTime check_in { get; set; }
public virtual DateTime check_out { get; set; }
public virtual int customer_id { get; set; }
public virtual decimal room_cost { get; set; }
#region Navigation Properties
[ForeignKey("customer_id")]
public virtual Customer Customer { get; set; }
#endregion
}
public class Customer
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
public virtual ICollection<Rental> Rentals {get;set;}
}