Entity Framework v5 looks cool and I try to switch from Linq-to-SQL with existing MSSQL (Azure) database.
but tutorials about EF are too complex to follow.
The database schema is pretty simple as follows (generated by exist db).
Sheets and SheetDetails tables are connected with 1-to-many relationship.
CREATE TABLE [dbo].[Sheets] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Grade] FLOAT (53) CONSTRAINT [DF_Sheets_Grade] DEFAULT ((0)) NOT NULL,
[Title] NVARCHAR (255) CONSTRAINT [DF_Sheets_Title] DEFAULT ('') NOT NULL,
[Description] NVARCHAR (255) NULL,
[Difficulty] SMALLINT CONSTRAINT [DF_Sheets_Difficulty] DEFAULT ((0)) NOT NULL,
[Writer] NVARCHAR (255) CONSTRAINT [DF_Sheets_Writer] DEFAULT ('') NOT NULL,
[Tag] NVARCHAR (255) NULL,
[Duration] FLOAT (53) CONSTRAINT [DF_Sheets_Duration] DEFAULT ((0)) NOT NULL,
[Timestamp] DATETIME CONSTRAINT [DF_Sheets_Timestamp] DEFAULT ((0)) NOT NULL,
[RowVersion] ROWVERSION NOT NULL,
CONSTRAINT [PK_Sheets] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[SheetDetails] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Score] FLOAT (53) CONSTRAINT [DF_SheetDetails_Score] DEFAULT ((0)) NOT NULL,
[Number] SMALLINT CONSTRAINT [DF_SheetDetails_Number] DEFAULT ((0)) NOT NULL,
[SubNumer] SMALLINT NULL,
[IsRandom] BIT CONSTRAINT [DF_SheetDetails_IsRandom] DEFAULT ((0)) NOT NULL,
[AnswerType] SMALLINT CONSTRAINT [DF_SheetDetails_AnswerType] DEFAULT ((0)) NOT NULL,
[RowVersion] ROWVERSION NOT NULL,
[SheetDetail_Sheet] INT CONSTRAINT [DF_SheetDetails_SheetDetail_Sheet] DEFAULT ((0)) NOT NULL,
[SheetDetail_Question] INT CONSTRAINT [DF_SheetDetails_SheetDetail_Question] DEFAULT ((0)) NOT NULL,
CONSTRAINT [SheetDetail_Sheet] FOREIGN KEY ([SheetDetail_Sheet]) REFERENCES [dbo].[Sheets] ([Id]) ON DELETE CASCADE
);
Note that the FK name is SheetDetail_Sheet in SheetDetails table.
Result diagram is as below.
Next, maybe I need to write EntityTypeConfiguration.
I tried it as question 1.
Question 1.
I wrote model creating configuration as follows but no luck. is it wrong? hard to know how to write right configuration with this simple database model.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new SheetsConfiguration());
base.OnModelCreating(modelBuilder);
}
public class SheetsConfiguration : EntityTypeConfiguration<Sheets>
{
public SheetsConfiguration()
: base()
{
HasKey(p => p.Id);
Property(p => p.Id).HasColumnName("Id").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
Property(p => p.RowVersion).IsConcurrencyToken().IsRowVersion();
HasOptional(p => p.SheetDetails).WithMany().Map(x => x.MapKey("SheetDetail_Sheet"));
ToTable("Sheets");
}
}
I execute simple query using
var result = _db.Sheets.Where(sheet => sheet.Id == id).ToList();
And then, I got an error "Invalid column name SheetDetail_Sheet" with executed query as follows.
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Grade] AS [Grade],
[Extent1].[Title] AS [Title],
[Extent1].[Description] AS [Description],
[Extent1].[Difficulty] AS [Difficulty],
[Extent1].[Writer] AS [Writer],
[Extent1].[Tag] AS [Tag],
[Extent1].[Duration] AS [Duration],
[Extent1].[Timestamp] AS [Timestamp],
[Extent1].[RowVersion] AS [RowVersion],
[Extent1].[SheetDetail_Sheet] AS [SheetDetail_Sheet]
FROM [dbo].[Sheets] AS [Extent1]
WHERE [Extent1].[Id] = #p__linq__0
I can understand because SheetDetail_Sheet is just an FK and not exist in the edmx properties and database column.
How can I fix it?
I don't want to edit auto-generated model file because it can be overwritten. maybe it seems to be achieved with EntityTypeConfiguration.
Question 2.
Is there any useful and lightweight reference with the commonly used master-detail database model?
I'm in trouble to start with existing database.
stackoverflow, asp.net, blogs, etc...to many tutorials but hard to find an example like my case.
Thank you.
I'd suggest using Model First to create your database model (though you're using database first). A good article for getting the database model is here. Just ignore the MVC stuff, and stop at "Generating Strongly Typed Entity Classes" as you are using EF5 which will generate the POCO classes for you. The Edmx should handle all of the FKs and properties for you and you won't need to worry about the configurator.
Related
this is my code for table
CREATE TABLE [dbo].[product] (
[prod_Id] NUMERIC (5) NULL,
[barcode] NUMERIC (13) NULL,
[prod_name] NVARCHAR (50) NULL,
[price] FLOAT (53) NULL,
[stock] NUMERIC (18) NULL,
[cat_id] NCHAR (10) NULL,
[discount] FLOAT (53) NULL,
PRIMARY KEY CLUSTERED ([prod_Id],[barcode] ASC)
);
I have 2 primary keys prod_id and barcode. I want to make them null as user have choice either to enter prod_id or barcode. Both will not have value at same time. Now please anyone help me how to do it. I tried to make them null it gives syntax error.
Replace primary key with unique
unique CLUSTERED ([prod_Id],[barcode] ASC)
(or)
Give some default value to the columns that are there in the composite primary key.
CREATE TABLE [dbo].[product] (
[prod_Id] NUMERIC (5) default 0,
[barcode] NUMERIC (13) default 0,
[prod_name] NVARCHAR (50) NULL,
[price] FLOAT (53) NULL,
[stock] NUMERIC (18) NULL,
[cat_id] NCHAR (10) NULL,
[discount] FLOAT (53) NULL,
PRIMARY KEY CLUSTERED ([prod_Id],[barcode] ASC)
);
If you are using C# and sending data from C# to SQL server then then you can have validation in place to check if 1 is null then other one must be not null and throw exception/error from there and make both the columns in DB as Unique not primary key. It might help.
In any database table, there is one and only one primary key and that primary key should not be null.
In your case, for each prod_id there will be unique barcode and vise versa. So, it won't make any sense making any one of this as NULL.
instead create 2 table, one containing table_id and other containing barcode and then refer one in another using foreign_key.
Ran into a small problem while working on EF 6 Database first approach.
When I try to insert a value into the key field of a table which is not set to be the Identity, I receive the following exception:
Cannot insert the value NULL into column 'emp_main_id',column does not allow nulls. INSERT fails.
The statement has been terminated.
I added the following code in the entity class to avoid the error
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int emp_main_id { get; set; }
but still could not get it working.
Below is the script to create the db table
CREATE TABLE [dbo].[EmployeesMain] (
[emp_main_id] INT NOT NULL,
[emp_main_first] NVARCHAR (40) NOT NULL,
[emp_main_middle] NVARCHAR (40) NULL,
[emp_main_last] NVARCHAR (40) NOT NULL,
[emp_main_dob] DATE NOT NULL,
[emp_main_gender] INT DEFAULT ((1)) NOT NULL,
[emp_main_type] INT DEFAULT ((0)) NOT NULL,
[emp_main_email] NVARCHAR (150) NOT NULL,
[emp_main_password] NVARCHAR (MAX) NOT NULL,
[emp_main_designation] NVARCHAR (150) NULL,
[emp_main_skill] NVARCHAR (MAX) NULL,
[emp_main_contract] INT DEFAULT ((0)) NOT NULL,
[emp_main_lead] NVARCHAR (81) NULL,
[emp_main_img] NVARCHAR (MAX) NULL,
[emp_main_doj] DATE DEFAULT ('01-JAN-2012') NULL,
CONSTRAINT [emp_main_primary_key] PRIMARY KEY ([emp_main_id])
);
Any help on this will be appreciated.
Problem is you are trying to insert NULL value to a Primary Key
column i.e emp_main_id.
Primary Key doesn't allow to insert NULL values or duplicate values.
If you want to insert NULL values remove Primary Key constraint.
Decided to write the answer myself.
The problem was, since I had set the field as an identity earlier, the values for the field were being generated automatically. Even after removing the identity and updating the model from the database, this was not reset.
So what I had to do was,
Go to the .edmx file.
Right click on the property "emp_main_id"
Click on Properties
Set StoreGeneratedPatter to None
Save the model and rebuild the solution
That's it. it gives me a non-identity key, with all the other constraints along with the option to explicitly enter a value for the field. Peace :)
I'm trying to publish a version of 'GeekQuiz' to azure as a webapp. It looks like I've managed to get everything exported except the database since information isn't being loaded in at all.
The TriviaContext is where the database appears to be created:
public class TriviaDatabaseInitializer : CreateDatabaseIfNotExists<TriviaContext>
However there were no databases defined in manage.windowsazure.com, so I created one (sql database) and got the connection string for it and ran that via the packagemanager console (Update-Database -Verbose -ConnectionString ...) then I ran Enable-Migrations -ContextTypeName GeekQuiz.Models.TriviaContext.
Everything seems to have run without issues but the webapp still doesn't work and I'm pretty sure it's because the database is not being created.
Is there any steps I can take to diagnose this problem or am I doing something wrong? I'm very new to this and I couldn't find any tutorials or info on publishing a database so I could be completely off base here.
When I run the seed method this is the SQL I'm seeing, notice there is no data being input for trivia:
CREATE TABLE [dbo].[TriviaAnswers] (
[QuestionId] [int] NOT NULL,
[OptionId] [int] NOT NULL,
[Id] [int] NOT NULL IDENTITY,
[UserId] [nvarchar](max),
CONSTRAINT [PK_dbo.TriviaAnswers] PRIMARY KEY ([Id])
)
CREATE TABLE [dbo].[TriviaOptions] (
[QuestionId] [int] NOT NULL,
[Id] [int] NOT NULL IDENTITY,
[Title] [nvarchar](max) NOT NULL,
[IsCorrect] [bit] NOT NULL,
CONSTRAINT [PK_dbo.TriviaOptions] PRIMARY KEY ([QuestionId], [Id])
)
CREATE TABLE [dbo].[TriviaQuestions] (
[Id] [int] NOT NULL IDENTITY,
[ImageClip] [nvarchar](max),
[ImageDir] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_dbo.TriviaQuestions] PRIMARY KEY ([Id])
)
CREATE INDEX [IX_QuestionId_OptionId] ON [dbo].[TriviaAnswers]([QuestionId], [OptionId])
CREATE INDEX [IX_QuestionId] ON [dbo].[TriviaOptions]([QuestionId])
ALTER TABLE [dbo].[TriviaAnswers] ADD CONSTRAINT [FK_dbo.TriviaAnswers_dbo.TriviaOptions_QuestionId_OptionId] FOREIGN KEY ([QuestionId], [OptionId]) REFERENCES [dbo].[TriviaOptions] ([QuestionId], [Id]) ON DELETE CASCADE
ALTER TABLE [dbo].[TriviaOptions] ADD CONSTRAINT [FK_dbo.TriviaOptions_dbo.TriviaQuestions_QuestionId] FOREIGN KEY ([QuestionId]) REFERENCES [dbo].[TriviaQuestions] ([Id]) ON DELETE CASCADE
CREATE TABLE [dbo].[__MigrationHistory] (
[MigrationId] [nvarchar](150) NOT NULL,
[ContextKey] [nvarchar](300) NOT NULL,
[Model] [varbinary](max) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY ([MigrationId], [ContextKey])
)
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'201509240441274_AutomaticMigration', N'GeekQuiz.Models.TriviaContext', 0x1F8B0800000000000400ED5ADD6EDB3614BE1FB0771074B50DA915A7375B60B7489DA408D6246DEC16BB0B68E9D8214A511A496576873DD92EF6487B851DFD4BD48F253B4ED262C84D4CF3FCF0F07C3CE477FCEFDFFF8C5EAF5C66DC8390D4[snip (lots of stuff here)] , N'6.1.1-30610')
Building my own mini CMS back end in EF + SQL Server (Database First). I have a "Contents" table which all entities link too using a Foreign Key.
CREATE TABLE [dbo].[Contents](
[ContentID] [int] IDENTITY(1,1) NOT NULL,
[ContentType] [varchar](100) NOT NULL,
[DateAdded] [datetime] NOT NULL,
[DateUpdated] [datetime] NULL,
[isDeleted] [bit] NOT NULL,
[UserId] [int] NOT NULL
CREATE TABLE [dbo].[Articles](
[ArticleID] [int] IDENTITY(1,1) NOT NULL,
[ContentID] [int] NOT NULL,
[ImageID] [int] NOT NULL,
[ArticleHeadline] [varchar](250) NOT NULL,
[ArticleSummary] [nvarchar](200) NOT NULL,
[ArticleBody] [nvarchar](500) NOT NULL
ALTER TABLE [dbo].[Articles] WITH CHECK ADD CONSTRAINT [FK_Articles_Contents] FOREIGN KEY([ContentID])
REFERENCES [dbo].[Contents] ([ContentID])
In Entity Framework the Entity Content quite rightly thinks that this is a one to many relationship. How do I go about making this one to one? Content can only belong to one other Entity but I keep having to use First() in my code.
<h1>#Model.Content.Articles.First().ArticleHeadline</h1>
#Html.Raw(Model.Content.Articles.First().ArticleBody)
As for database first approach, to have 1-1 association in EF, the dependent ([dbo].[Articles]) must have a primary key that also is the foreign key to the principal([dbo].[Contents]). It will require some DB design change like this:
CREATE TABLE [dbo].[Contents](
[ContentID] [int] NOT NULL PRIMARY KEY,
[ContentType] [VARCHAR](100) NOT NULL
)
CREATE TABLE [dbo].[Articles](
[ContentID] [int] NOT NULL PRIMARY KEY,
[ImageID] [int] NOT NULL,
CONSTRAINT [FK_Contents] FOREIGN KEY ([ContentID]) REFERENCES [dbo].[Contents] ([ContentID]) ON DELETE CASCADE
)
This should answer your question
http://www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx
Look at the fluent configuration
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
// Configure StudentId as PK for StudentAddress
modelBuilder.Entity<StudentAddress>() .HasKey(e => e.StudentId);
// Configure StudentId as FK for StudentAddress
modelBuilder.Entity<StudentAddress>() .HasRequired(ad => ad.Student) .WithOptional(s => s.StudentAddress); }
Replace student address and student with article content and article
For db first mappings you will need to modify your edmx and regenerate your models.
This may help:
http://www.exceptionnotfound.net/entity-framework-for-beginners-creating-a-database-first-model/
When I use a database initializer like DropCreateDatabaseAlways or MigrateDatabaseToLatestVersion to create my Entity Framework (5.0.0) database, the resulting schema does not include the indexes that I defined in my migrations, unlike when I create the database using Update-Database.
How can I configure the system so that it produces the same end result using a database initializer as it would when running the migrations in sequence?
Example migration
public override void Up()
{
CreateIndex("dbo.Users", "Username", unique:true);
}
Result from DropCreateDatabaseAlways (no index)
CREATE TABLE [dbo].[Users] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
[Username] NVARCHAR (50) NULL,
[Email] NVARCHAR (255) NULL,
CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ([Id] ASC)
);
Result from Update-Database (includes index)
CREATE TABLE [dbo].[Users] (
[Id] BIGINT IDENTITY (1, 1) NOT NULL,
[Username] NVARCHAR (50) NULL,
[Email] NVARCHAR (255) NULL,
CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_Username]
ON [dbo].[Users]([Username] ASC);
The approach you have used is the "manual" code first migrations. Where you get to fiddle with the script. Automated migrations or drop create, EF just bangs a script together to match the table and Foreign keys and pops it out there. ie what you would have seen in the generated class before you added code. :-)
Use Automated Migrations/Create scenarios and just call SQL Command direct afterwards to add indexes from code. You have the SQL code to create indexes. Just trigger the initializer and follow up with create Index custom routine.