How to create tables in codefirst approach - c#

I am working on Login page creating in C# using Code First approach , in this I am getting lot of errors while trying to execute the code. I am a fresher and new to this .
Can you please review my code and help me what I missed in this ?
Rule are not creating and getting the multiple errors. Your help would help me to understand what went wrong in this.
My Class "Class1.cs"
public class Login
{
[Required]
public string username { get; set; }
[Required]
public string password{ get; set; }
}
}
public class LoginContext : DbContext
{
public LoginContext() : base("LoginDBConnectionString")
{
Database.SetInitializer<LoginContext>(new DropCreateDatabaseIfModelChanges<LoginContext>());
}
public DbSet<username> username { get; set; }
public DbSet<password> password { get; set; }
}
Context.cs
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Web;
using System.Web.UI.WebControls;
using System.Data.Entity;
using Jquery1.Models;
namespace Jquery1.Models
{
public class Logincontext: DbContext
{
public Logincontext () : base ("LoginDBConnectionString")
{
}
public DbSet<Login> Logins{ get; set; }
}
}
class program
{
static void Main(string[] args)
{
using (var ctx = new Logincontext())
{
ctx.Database.Create();
}`enter code here`
}
}

Hi Let me explain this using fluent api bear with me a little please,
Create Your DbContext First:
public class MyDbContext : DbContext
{
public MyDbContext()
: base("name=MyConnection")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, YourApplication.Migrations.Configuration>("MyConnection"));
}
public DbSet<Users> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//here you can MAP Your Models/Entities, but i am going to show you something more interesting. so keep up.
modelBuilder.Configurations.Add(new UsersMap());
}
}
Create a Migration Folder in your app root And make Configuration class there(Why?! so that everytime you made a change migration of EF will update the Tables for you):
internal sealed class Configuration : DbMigrationsConfiguration<YourApplication.Infrastructure.Data.MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
//this feature on true can result in unwanted/unexpected dataloss
AutomaticMigrationDataLossAllowed = true;
ContextKey = "YourApplication.Infrastructure.Data.MyDbContext";
}
protected override void Seed(YourApplication.Infrastructure.Data.MyDbContext context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
Now Go on And Create Your POCO Classes. I try to write my codes very clean. That's why when for example i made a Model like below, i create an EntityBase for every Id:
public class EntityBase
{
public int Id { get; set; }
}
And Implement it to my Model :
public class User: EntityBase
{
public string Example1{ get; set; }
public string Example2{ get; set; }
public string Example3{ get; set; }
}
And For Mapping I Create another Class like below and use Fluent Api:
public class UserMap : EntityTypeConfiguration<User>
{
public UserMap()
{
//declaring the table name
ToTable("TblUser");
//declaring primary key of the table
HasKey(x => x.Id);
//declaring a property from poco class is required
Property(x => x.Example1)
.IsRequired();
//etc
}
}
be aware if you are using fluent api, you Shouldn't use Data Annotations. Happy Coding.

Entity frame-work uses a concept of standards-or-else. If you want your items fairly standard, you don' have to provide a lot of information. If you want your tables to have different names, or your columns to be different than standard you'll have to provide extra information using either Attributes (the method you use) or fluent API.
Every class that should become a table should have an Primary key. The default is to give your class a property Id, or to give the property the name of your class followed by Id:
public class Login
{
public int Id {get; set;}
public string UserName {get; set;}
public string Password {get; set;}
}
public class MyDbContext : DbContext
{
public DbSet<Login> Logins {get; set;}
}
This should be enough to give you a table with the default name, which is the plural of your class name Logins. Each record in the table has three columns:
Id: the primary key
UserName: a string, which in this case may be null
PassWord: a string which may be null.
Your Requires attribute will ensure that your UserName and Property are not null, but they won't prevent them being empty. I'm not sure that's enough for you.
Instead of Id your are free to use LoginId as foreign key:
public int LoginId {get; set;}
You'll see both methods used. Both have their advantages. The use of Id shows you immediately which property is the primary key. LoginId could also be used as foreign key. The name LoginId alone is not enough to see whether it is a primary key or a foreign key.
The defaults are usually plurals for collections of items where the item is the singular form. Here you'll see Login as class, and Logins as a set of objects of this class.
The article that helped me a lot to get on track using Entity Framework was this entity framework tutorial
The tutorial tells you about how to use defaults, how to create one-to-many relations with foreign keys, many-to-many, various inheritance strategies, and what to do if you are not satisfied with a default model.

Related

One to One HasRequired configuration not working

I have two sets of objects: Coupon and DiscountScheme.
Each have a connected object of {Type}Action, and identical configurations.
When making a request for Coupon, I do not get anything back,
but the same query for DiscountScheme works as expected
A condensed version of the classes (The full code and sql for the tables can be found here):
public class CouponAction
{
public int Id { get; set; }
public virtual Coupon Coupon { get; set; }
}
public class Coupon
{
public int Id { get; set; }
public virtual CouponAction Action { get; set; }
}
public class DiscountSchemeAction
{
public int Id { get; set; }
public virtual DiscountScheme DiscountScheme { get; set; }
}
public class DiscountScheme
{
public int Id { get; set; }
public virtual DiscountSchemeAction Action { get; set; }
}
The configuration:
public class CouponActionMap : EntityTypeConfiguration<CouponAction>
{
public CouponActionMap()
{
ToTable("CouponAction");
}
}
public class CouponMap : EntityTypeConfiguration<Coupon>
{
public CouponMap()
{
ToTable("Coupon");
HasRequired(c => c.Action);
}
}
public class DiscountSchemeActionMap : EntityTypeConfiguration<DiscountSchemeAction>
{
public DiscountSchemeActionMap()
{
ToTable("DiscountSchemeAction");
}
}
public class DiscountSchemeMap : EntityTypeConfiguration<DiscountScheme>
{
public DiscountSchemeMap()
{
ToTable("DiscountScheme");
HasRequired(ds => ds.Action);
}
}
The query I am trying to make:
using(var context = new Context()/* My database context, using a custom wrapper framework*/)
{
Console.WriteLine(context.Coupons.ToList()); // nothing
Console.WriteLine(context.DiscountSchemes.ToList()); // the contents of the table
}
If I query the actions table, I do get the contents, but again for CouponAction I do not get the connected Coupon, and for DiscountScheme it works as expected.
The issue is with your 1-to-1 relationship. By default EF expects a 1-to-1 to be using the PKs on both tables. By putting a CouponID on your CouponAction you are not setting a 1-to-1 relationship, you are setting a 1-to-many/many-to-1. Nothing stops several CouponAction records from having the same CouponId. You could put a unique constraint on CouponID, but if that were the case then you may as well have the CouponAction's PK to be the CouponID. Hence, this is why I don't advise using "Id" as a PK name, but rather CouponId vs. DiscountId, etc.
If the relationship between coupon and action is truly 1-to-1 then get rid of the CouponId on the Action table, and ensure you're using the same ID value across both tables for the related records. You can test this by changing your mapping to configure EF to use CouponId on the CouponAction as it's PK. Once you do that, you should see your related records coming up.
Alternatively you can establish a many to 1 relationship (HasOne.WithMany()) from Action to Coupon, but no return reference without a CouponActionId on Coupon. Or you can set up a 1-to-many where Coupon contains an ICollection<CouponAction> CouponActions even though you intend to only have one action per coupon. But if it is 1-to-1 then I would highly recommend using the same PK value across both tables.

Creating a common audit column in EF6 with inheritance

I have an existing database that has auditing on some tables with effectively temporal table functionality behind them (records get timestamped when changed and previous versions are stored in a history table, this is taken care by SQL and not EF/app logic).
There is a TPC Table-Per-Concrete-Class inheritance model being used. I have simplified the problem in the code below (Console app that will create a db called EfAudit on local).
Table Supplier already has an audit column on it, called ChangedBy, which works perfectly.
But Supplier is a specialised type of Organisation, normally Organisation is sufficient to store all the information required for an organisation - hence it not being marked as abstract.
I now need to record when the Organisations table has been updated with a ChangedBy field. But when I add it to the model/ef only the underlying Organisations table is ever updated.
I know with EFCore you can use Shadow Properties to do similar work, but this system is built on Framework and not Core and switching isn't feasible.
I have tried setting the CurrentValues for the column explicitly on each entity, but only the base table ever has the value written to it. I've tried blocking the base class in C# with the new keyword. I cannot find out how I achieve this with EF6.
using System;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration;
using System.ComponentModel.DataAnnotations.Schema;
namespace EfAuditTest
{
class Program
{
static void Main(string[] args)
{
Context cxt = new Context();
cxt.Suppliers.Add(new Supplier() // Some test data
{
Name = "Acme Inc",
ContractStart = DateTime.Now,
});
cxt.Organisations.Add(new Organisation() // A generic organisation that isn't a supplier
{
Name = "Just a business"
});
cxt.SaveChanges();
}
}
#region Model
interface IAudit // An auditing interface applicable to most database tables
{
string ChangedBy { get; set; }
}
public abstract class Base // Common table stuff
{
public int Id { get; set; }
}
public class Organisation : Base, IAudit // An organisation, concrete as sometimes has everything needed
{
public string Name { get; set; }
public string ChangedBy { get; set; } = "Application User 42";
}
public class Supplier : Organisation // A specialised organsiation that extends with some extra fields
{
public DateTime ContractStart { get; set; } = DateTime.Now;
}
#endregion
#region Schema
public class OrganisationSchema : EntityTypeConfiguration<Organisation>
{
public OrganisationSchema()
{
Map(m =>
{
m.ToTable("Organisations");
});
HasKey(m => m.Id)
.Property(m => m.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
/* THIS BIT HERE
* If I add this to the Organisation table, it stops working in the Supplier table. */
Property(p => p.ChangedBy);
}
}
public class SupplierSchema : EntityTypeConfiguration<Supplier>
{
public SupplierSchema()
{
Map(m =>
{
m.ToTable("Suppliers");
});
/* THIS BIT HERE
* This mapping is now ignored by EF, and only the one in OrgansiationSchema is updated on writes */
Property(p => p.ChangedBy);
}
}
#endregion
#region Context
public class Context : DbContext
{
public virtual DbSet<Organisation> Organisations { get; set; }
public virtual DbSet<Supplier> Suppliers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new OrganisationSchema());
modelBuilder.Configurations.Add(new SupplierSchema());
base.OnModelCreating(modelBuilder);
}
public Context() : base("Server=(local);Database=EfAudit;Integrated Security=SSPI")
{
}
}
#endregion
}
Many thanks for any answers!

EF Core - Reuse the same join table entity for several relationships

I want to reuse the same many-to-many relationship table (FileInEntity) for several other objects (Course, Lecture, Game), since they all can have files. Since we have to manually create the many-to-many relationships by creating a join entity, I want to reuse the join entity for the objects (Course, Lecture, Game).
If we look at the table structure, I would like to have the following:
Course: Id, ...
Lecture: Id, ...
Game: Id, ...
FileInEntity: EntityId (this can be either Course.Id, Lecture.Id or Game.Id), FileId
File: Id, ...
(File is base class type with two derived types: Image and Audio)
When I try this approach in .NET Core, I receive the following error message:
Entity type 'FileInEntities' is in shadow-state. A valid model requires
all entity types to have corresponding CLR type.
Is this even possible?
This is my setup:
ModelBase.cs
public class ModelBase
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
}
Course.cs
[Table("Courses")]
public class Course : ModelBase
{
private ICollection<FileInEntity> IconsInCourse { get; set; } = new List<FileInEntity>();
[NotMapped]
public File Image => IconsInCourse.Select(e => e.File).FirstOrDefault();
}
Lecture.cs
// Same as Course.cs
Game.cs
// Same as Course.cs
FileInEntity.cs
[Table("FilesInEntities")]
public class FileInEntity
{
public Guid FileId { get; set; }
public Guid EntityId { get; set; }
public virtual ModelBase Entity { get; set; }
public virtual File File { get; set; }
}
File.cs
[Table("Files")]
public class File : ModelBase
{
// This is the property for which the error occured
private ICollection<FileInEntity> FileInEntities { get; set; } = new List<FileInEntity>();
public IEnumerable<ModelBase> Entities => FileInEntities.Select(e => e.Entities);
}
FilesInEntitiesMap.cs (Relationship Configuration)
builder.HasOne(p => p.Entity)
.WithMany()
.HasForeignKey(k => k.EntityId);
builder.HasOne(p => p.File)
.WithMany()
.HasForeignKey(k => k.FileId);
FileMap.cs
// This is the key to which the error references to
builder.HasMany("FileInEntities")
.WithOne("Entity")
.HasForeignKey("EntityId");
You won't be able to use the base class ModelBase as the object in the mapping class because c# wont know the actual type coming back from the db. You can look at table per hierarchy inheritance, but I'm still not sure you would be able to use that in a mapping table either. Here is a good article
If your Course.cs, Lecture.cs, and Game.cs are the same and the only difference is type, you could combine them into one class and add an enum property to set the type.
public enum EntityType{
Game = 1,
Lecture = 2,
Course = 3
}
public class MyEntity : ModelBase{
private ICollection<FileInEntity> Icons { get; set; } = new List<FileInEntity>();
[NotMapped]
public File Image => Icons.Select(e => e.File).FirstOrDefault();
public EntityType EntityType {get;set;} //course, lecture, or game
}
When you care about the type just use a where clause.
Be sure to use Fluent Api in DbContext's OnModelCreating to determine One to One relationship for this tables. (and be sure again correct reference properties are selected)
Missing parts of your codes.
public class ModelBase
{
[Key]// add for primary key
//set none always for primary keys (because guid has no auto increment)
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
}
[Table("Files")]
public class File : ModelBase
{
//make it public
public ICollection<FileInEntity> FileInEntities { get; set; } = new List<FileInEntity>();
[NotMapped] //set not mapped
public IEnumerable<ModelBase> Entities => FileInEntities.Select(e => e.Entities);
//do it same changes for `Lacture.cs`, `Game.cs` and `Course.cs`...
}

Persist List of same Class

As someone coming from JPA to C# .Net and Entity framework, I'm having a really hard time wrapping my head around the lack of support for lists in EF.
I need to do the following:
public class Foo {
public long Id {get; set;}
//Class value objects / attributes
//e.g
public string Name {get; set;}
public AnotherFoo AFoo {get; set;}
//This class can have many children classes of the same type
//In this case Foo can have many Foo's
public List<Foo> {get; set;}
}
However, I'm not sure how to go on persisting this. I've seen articles about Hierarchical Data Management and I tried implementing them but with no success. All went fine untill I had to query the 'List' then, I would get a recursive error which I don't remember exactly what it was.
I've also searched in stackoverflow, but could not pinpoint my problem.
TL;DR
I want to persist a class that has a list of itself in Entity Framework /.Net Core, how would I go on about it?
I'd really appreciate it if anyone could give me a hand on this! Thanks in advance.
The problem with your implementation is that you don't describe your schema to Entity Framework, i.e you don't define the relationships between you objects.
Here is a suggestion that works:
public class Foo
{
public int ID { get; set; }
public string Name { get; set; }
[ForeignKey("AFoo")]
public int? AFooID { get; set; }
public virtual AnotherFoo AFoo { get; set; }
public int? ParentID { get; set; }
public virtual Foo Parent { get; set; }
public virtual List<Foo> Children { get; set; } = new List<Foo>();
}
public class AnotherFoo
{
public int ID { get; set; }
public string Name { get; set; }
}
Please note a couple of things:
I have added a foreign key property AFooID to the AFoo entity. Entity Framework will recognize on its own the relationship between AFoo property and Foo entity and when building the schema it will also add a foreign key to AntoherFoo entity. But this key will not be available in your code because you didn't add it to the Foo class properties. Also, it is better that you have the complete control over the scema creation and don't let much to Entity Framework's imagination (which is quite good nevertheless).
A have added an annotation [ForeignKey("AFoo")] over AFooID to define that this is a foreign key to AFoo navigation parameter. Normally I should also add a similar annotation over ID to define it as a primary key, but Entity Framework does this automatically for an integer property named ID.
I have used the virtual keyword on all navigation parameters to allow lazy loading of those parameters.
Now, for your prime question; You can create a reference of children of the same type as if it was any other type. But you have to describe the relationship! In this example I configure an one to many relationship, meaning that each foo can have only one parent but many children. To do this I used Fluent API:
public class MyContext: DbContext
{
public DbSet<Foo> Foos { get; set; }
public DbSet<AnotherFoo> AFoos { get; set; }
public MyContext()
: base("TestDB")
{
Configuration.LazyLoadingEnabled = true;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Foo>()
.HasOptional(f => f.Parent)
.WithMany(f => f.Children)
.HasForeignKey(f => f.ParentID)
.WillCascadeOnDelete(false);
}
}
Override the OnModelCreating method of your DbContext class to specify more "fluently" your database schema.
Now run the following commands in your Package Manager Console to create your database:
add-migration InitialDB
It will create a cs file that describes the schema to be created. Check that is as you desired.
update-database
It will create a database using the connection string defined in your config file and the schema from the file above.
Run this demo application:
static void Main(string[] args)
{
var foo = new Foo { Name = "parent foo" };
var foo1 = new Foo { Name = "first foo child" };
var foo2 = new Foo { Name = "second foo child" };
foo.Children.Add(foo1);
foo.Children.Add(foo2);
using(var context = new MyContext())
{
context.Foos.Add(foo);
context.SaveChanges();
}
// another transaction to read the saved data
using(var context = new MyContext())
{
var readfoo = context.Foos.FirstOrDefault();
Console.WriteLine($"{readfoo.Name} has the following children:");
foreach(var child in readfoo.Children)
Console.WriteLine(child.Name);
}
Console.ReadKey();
}
The results is as expected:
I hope I helped you solve your problem and understand a bit more the world of Entity Framework.

Configuring a relationship that uses Table Splitting in EF Core 2

I'm trying to build my first Table Splitting in EF Core 2 using fluent configuration.
I have two simple entities named User and Customer and I want use them in single table named "AppUsers". So I created a simple entity classes for both:
User.cs
public partial class User
{
public long Id { get; set; }
public string Name { get; set; }
public Customer Customer { get; set; }
}
And:
Customer.cs
public partial class Customer
{
public long Id { get; set; }
public Guid CustomerGuid { get; set; }
public User User { get; set; }
}
Then I make changes to MyDbContext as:
MyDbContext.cs
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOne(c => c.Customer).WithOne(c => c.User)
.HasForeignKey<Customer>(e => e.Id);
modelBuilder.Entity<User>().ToTable("AppUsers");
modelBuilder.Entity<Customer>().ToTable("AppUsers");
base.OnModelCreating(modelBuilder);
}
}
And then I created a migration using Add-Migration "Simple_Test" without errors. So I run Update-Database that worked fine without console error but when I trying to run app getting this error:
The entity of 'User' is sharing the table 'AppUsers' with 'Customer', but there is no entity of this type with the same key value that has been marked as 'Added'
I cant understand this. I'm student just started learning about relationship configuration. Any idea please?
The issue is that each row in the database table now contains fields from two entities--one User and one Customer. This means that every time a User is created and saved, there must also be a Customer created and saved with the same Id, because the database row cannot hold only a User or only a Customer, it must have both.
I added Customer seed's in another method that's my fool. That must be in User seed's. var user = new User();
user.Customer = new Customer { Id = user.Id }

Categories