OK 2 questions:
1. I am new to Databases and I want to learn the code first approach to creating a Database. I have used the Model-first approach a few times. Can anyone help me with coding this DB using Code-first approach (I also would like to add an Employee table if possible)?
Here is the link to the DB Diagram:
http://databaseanswers.org/data_models/customers_and_orders/images/customers_and_orders_ref_data_model.gif
Also, how would I insert into lets say the customer table / customer address address all in one go, using entity framework of course?
Thank you in advance for anyone willing to help.
You can do it like follows:
Please note the this solution has done as a console application.
Please add the following class to do this as code first:
public class Customer
{
[Key]
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
public string CustomerOtherDetails { get; set; }
}
public class CustomerAddress
{
[ForeignKey("Customer")]
public int CustomerId { get; set; }
[ForeignKey("AddressType")]
public int AddressTypeId { get; set; }
[ForeignKey("Address")]
public int AddressId { get; set; }
[Key]
public DateTime DateFrom { get; set; }
public DateTime DateTo { get; set; }
public virtual Customer Customer { get; set; }
public virtual AddressType AddressType { get; set; }
public virtual Address Address { get; set; }
}
public class AddressType
{
[Key]
public int AddressTypeId { get; set; }
public string AddressTypeDescriptiom { get; set; }
}
public class Address
{
[Key]
public int AddressId { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string City { get; set; }
}
When you do it Code First approach you need to create the model out of the class you created and it can be done as follows:
Context class should be like follows:
public class CustomerContext : DbContext
{
public CustomerContext()
: base("DBConnectionString")
{
//If model change, It will re-create new database.
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<CustomerContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Set primary key to Customer table
modelBuilder.Entity<Customer>().HasKey(m => m.CustomerId);
//set primary key to Address table
modelBuilder.Entity<CustomerAddress>().HasKey(m => m.DateFrom);
modelBuilder.Entity<AddressType>().HasKey(m => m.AddressTypeId);
modelBuilder.Entity<Address>().HasKey(m => m.AddressId);
//Set foreign key property
modelBuilder.Entity<CustomerAddress>().HasRequired(t => t.Customer)
.WithMany().HasForeignKey(t => t.CustomerId);
modelBuilder.Entity<CustomerAddress>().HasRequired(t => t.AddressType)
.WithMany().HasForeignKey(t => t.AddressTypeId);
modelBuilder.Entity<CustomerAddress>()
.HasRequired(t => t.Address)
.WithMany()
.HasForeignKey(t => t.AddressId);
}
Database creating and the inserting address with a customer should be like below:
static void Main(string[] args)
{
using (var ctx = new CustomerContext())
{
//ctx.Database.Create(); // This command can be used to create the database using the code first class
ctx.CustomerAddresses.Add(new CustomerAddress
{
AddressType = new AddressType
{
AddressTypeId = 1,
AddressTypeDescriptiom = "Test"
},
Customer = new Customer
{
CustomerId = 1,
FirstName = "Customer 1"
},
Address = new Address
{
Line1 = "Line 1",
City = "USA"
},
DateFrom = DateTime.Now,
DateTo = DateTime.Now
});
ctx.SaveChanges();
}
}
Connection string should like below:
<connectionStrings>
<add name="DBConnectionString"
connectionString="Data Source=(local);Initial Catalog=CustomerDB;Integrated Security=true"
providerName="System.Data.SqlClient"/>
</connectionStrings>
Please note following note the above code need following references.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
I tried this and it works as you expected. Please let me know whether you need a sample project on this.
Hope this helps you.
EDITED:
To configure self reference in code first please do as below:
public class Product
{
[Key]
public int ProductId { get; set; }
public int? ParentProductId { get; set; }
public virtual Product ParentProduct { get; set; }
}
Add the following code lines in OnModelCreating method:
modelBuilder.Entity<Product>().HasKey(m => m.ProductId);
modelBuilder.Entity<Product>().
HasOptional(e => e.ParentProduct).
WithMany().
HasForeignKey(m => m.ParentProductId);
For the Employee Table, You Can create a class (Employee.cs):
public class Employees
{
public string FName {get;set;}
public string LName {get;set;}
public string Position {get;set;}
public string Email {get;set;}
[Display(Name = "Full Name")]
public string FullName
{
get
{
return LName + ", " + FName;
}
}
}
For the insert, You can do :
var users = new List<User>
{
new User{FName ="Chris", LName ="Fajardo",Position=#"Dev",Email="test.test#test.ae"}
};
users.ForEach(s => context.User.Add(s));
context.SaveChanges();
Related
I'm working through Robert Beasley's book on ASP.NET Core and Razor Pages and I'm currently trying to add a row of data to a table using Entity Framework Core. I'm getting an "invalid column name" error for column EmployeeID1. That makes sense because EmployeeID is my Key for the Employee table, I don't have a column EmployeeID1. It seems the error is occurring when .SaveChangesAsync() runs; I can't figure out why the .SaveChangesAsync() method is finding a need to append a 1 to the end of my column name.
I'm looking at:
MaintainInsert.cshtml.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Chapter21.Models;
using System.Diagnostics;
namespace Chapter21.Pages
{
public class MaintainInsertModel : PageModel
{
private readonly Chapter21
.Models.SportsPlayContext SportsPlayContext;
public MaintainInsertModel(Chapter21
.Models.SportsPlayContext SPC)
{
SportsPlayContext = SPC;
}
public async Task OnGetAsync()
{
Employee Employee = new Employee();
Employee.LastName = "Westbrook";
Employee.FirstName = "Russell";
Employee.MiddleInitial = "E.";
Employee.Address = "123 Road Rd";
Employee.City = "Los Angeles";
Employee.State = "California";
Employee.ZipCode = "12312";
Employee.Phone = "123-123-1234";
Employee.EmailAddress = "russw#gmail.com";
Employee.Password = "gimm3";
Employee.Status = "S";
SportsPlayContext.Employee.Add(Employee);
await SportsPlayContext.SaveChangesAsync();
}
}
}
Here is the scaffolded Employee.cs class
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
#nullable disable
namespace Chapter21.Models
{
public partial class Employee
{
public Employee()
{
Orders = new HashSet<Orders>();
}
public int EmployeeId { get; set; }
[Key]
public int EmployeeID { get; internal set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public string Phone { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string Status { get; set; }
public virtual ICollection<Orders> Orders { get; set; }
}
}
An earlier point of confusion was why did it generate both EmployeeId and EmployeeID, but I was able to figure out some problems that caused me - unless this one is also related.
This is the database I'm using: https://github.com/rbeasley-rezine/ASP.NET-Core-Razor-Pages
When I comment out await SportsPlayContext.SaveChangesAsync();
I don't get the error message, but then of course it does not save the changes to the table.
I've tried adding the EmployeeID property to the new Employee object, which should be unnecessary because it's the key, and I've tried countless other things which I don't remember now.
I'll be happy to provide more info if I've not provided enough context.
Hello I want to sort my end result using related entity property which is in this case Locality. I got the keyword from client end as a string that includes column name and sort direction eg. "locality=asc" but when I do orderby with any parent entity properties it run fine however, the property with related entity gives me an error by saying that customer object does not have any locality property
here is my both class customer and Address
public class Customer : IEntity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
public Guid UserId { get; set; }
public DateTime DateCreated { get; set; }
public DateTime LastUpdated { get; set; }
[ForeignKey("Address")]
public Guid AddressId { get; set; }
public virtual Address Address { get; set; }
}
public class Address: IEntity
{
public Guid Id { get; set; }
public string Lat { get; set; }
public string Lon { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Locality { get; set; }
}
Here I am trying to sort it with Address property like locality
int skip = (pageNum - 1) * pageSize;
if (skip < 0)
{
skip = 0;
}
searchTerm = searchTerm.ToLower();
var query = _context.Customers.Include(q => q.Address)
.Where(c => c.FirstName.ToLower().Contains(searchTerm)
|| c.LastName.ToLower().Contains(searchTerm)
|| c.Email.ToLower().Contains(searchTerm)
|| c.Mobile.ToLower().Contains(searchTerm));
//var sortOrderSplit = sortOrder.Split('=');
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderByField("Email", "asc");
}
{
query = query.OrderByField("locality", "asc"); //that gives me an error because type is Address not Customer
}
var customers = query
.Skip(skip)
.Take(pageSize)
.ToList();
u want order by Locality ASC,right?
I think Class type of query is IEnumerable,so you can use lumbda expression.
because Locality is in Address Class,should follow the flow Customer => Address => Locality,not only search property Locality.
if (sortOrderSplit[0].ToLower() != "locality")
{
query = query.OrderBy(o => o.Email);
}
else
{
query = query.OrderBy(o => o.Address.Locality);
}
If your two entity classes have One-to-One relationship, you must add
public Customer Customer { get; set; }
into your Address class too.
Do this and try again.
I am trying to add this information into my database. My SQL Server will generate the Id for each row in the table. However, for some reason my code is adding a "0" for Id and I cannot figure out why or where it is coming from and I need to remove it so that the database can just generate it.
Here is my code:
public class Contact
{
public Contact()
{
}
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string Email { get; set; }
[Column(TypeName = "ntext")]
[Required]
public string Message { get; set; }
[Column(TypeName = "date")]
[Required]
public DateTime Date { get; set; }
[Column(TypeName = "time")]
[Required]
public TimeSpan Time { get; set; }
}
public class Context : DbContext
{
public Context()
: base("ContactConnectionString")
{
}
public DbSet<Contact> ContactForm { get; set; }
}
public class ImportToDataBase
{
public static void SubmitToDatabase(string theMessage, string fullName, string emailAddress)
{
using (var db = new Context())
{
var contact = new Contact()
{
Email = emailAddress,
Message = theMessage,
Name = fullName,
Date = DateTime.Now.Date,
Time = DateTime.Now.TimeOfDay,
// ID is not set in here
};
db.ContactForm.Add(contact);
db.SaveChanges();
}
}
}
}
Try decorating your Id property with the following:
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
The Key attribute tells Entity Framework that the Id property is the primary key and should not be included in the insert statement.
As a best practice, you need to mark your id with Key and Identity Option.
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
For fluent API you can use as:
HasKey(i => i.ID);
Property(i => i.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
I have made simple model for example.
public class Publisher
{
public int Id { get; set; }
public string Title { get; set; }
public Address Location { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Address
{
public string Country { get; set; }
public string City { get; set; }
public string Street { get; set; }
public string HouseNumber { get; set; }
}
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public int LanguageId { get; set; }
public int? PublisherId { get; set; }
}
I need to get publishers with related books. I know how to do it using linq to entities. Is it possible to solve a problem using entity sql?
public class CatalogContext : DbContext {...}
public List<Publisher> GetByCity(string city)
{
var result = new List<Publisher>();
string queryString;
queryString = String.Format(#"SELECT VALUE row(a,b)
FROM CatalogContext.Publishers AS a
join CatalogContext.Books AS b on a.Id = b.PublisherId
WHERE a.Location.City = '{0}'", city);
var rows = ((IObjectContextAdapter)_context).ObjectContext.CreateQuery<DbDataRecord>(queryString).ToList();
return ???
}
Query returns required data but it's List<DbDataRecord> - list of pairs <publisher, book>. How to translate it to list of publishers with filled navigation property "Books"?
Is it possible to write query which directly returns List<Publisher>?
you can do the following:
var result = ObjectContext.Publishers.Include("Books").Include("Locations")
.Where(c => c.Location.City = "SOME_CITY").Select(c => c);
Include - basically joins the table.
Then you can drill down to books by doing the following:
var test = result[0].Books;
Why are you using direct sql command instead of Entity Framework code style?
I have a trouble with relationship in EF v4.I know that this question very popular, I tried to find something in Internet, but it didn't help.
I have class Person that has one-to-one with Address(Person has Address)
class Person
{
public int PersonId{get;set;}
public string FisrtName{get; set;}
...
public int AddressId{get;set;}
public virtual Address Address{get;set;}
}
class Address
{
public int AddressId{get;set}
public string Street{get;set;}
...
}
I assumed that it was one-to-one relationship, I followed all conventions in EF v4.
But when I create DB diagram of generated DB.I can't see any relations between Person and Address.I mean I see two tables without relations with keys on Person and key on Address
Another tables with like this relations creates one-to-many with key on Account and infinity on Address, but code same.I see in designer only one-to-many reletions and some cases I can see any relations between tables tha must be.
Please help me!Thank you for any help
P.S I thought it's trouble with designer when I add tables
If you are using code first you can customize the persistence mapping by using either a fluent code API or use attributes to refine the model. EF can resolve relationships through inference if you were to use a simple key name such as Id; in your case EF needs a hint that PersonID and AddressID are keys.
To use the attribute approach add a reference to System.ComponentModel.DataAnnotations in your project and a corresponding 'using System.ComponentModel.DataAnnotations;' in your source files as necessary. The following sample (EF 4.3.1) will generate a "one-to-many" relationship between the generated Addresses and Persons tables (you don't want a one-to-one in this case). After running the code, you will see the relationships in the SQL Server Database Diagram window.
class Program
{
static void Main(string[] args)
{
using (ContactsEntities entities = new ContactsEntities())
{
Address doeaddress = new Address() { Street = "1 Broadway", ZipCode = "01234" };
Address doeaddress2 = new Address() { Street = "2 Broadway", ZipCode = "01234" };
entities.Addresses.Add(doeaddress);
entities.Persons.Add(new Person() { FirstName = "Jane", LastName = "Doe", Address = doeaddress });
entities.Persons.Add(new Person() { FirstName = "John", LastName = "Doe", Address = doeaddress });
entities.Persons.Add(new Person() { FirstName = "Jim", LastName = "Doe", Address = doeaddress2 });
entities.SaveChanges();
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
[Table("Addresses")]
public partial class Address
{
public Address()
{
this.Persons = new HashSet<Person>();
}
[Key]
public int AddressID { get; set; }
[Required]
public string Street { get; set; }
[RegularExpression(#"^(\d{5}-\d{4}|\d{5}|\d{9})$")]
[Required]
public string ZipCode { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
[Table("Persons")]
public partial class Person
{
[Key]
public int PersonID { get; set; }
public int AddressID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[ForeignKey("AddressID")]
public virtual Address Address { get; set; }
}
public partial class ContactsEntities : DbContext
{
public DbSet<Address> Addresses { get; set; }
public DbSet<Person> Persons { get; set; }
}
Based on feedback, here is an example of a one-to-one (actually a one-to-zero-or-one) relationship. I've used the fluent API to set the relationships in the OnModelCreating override. In this scenario a person can have at most one photo row. In practice this might be useful if the Photos table contained one or more large byte arrays to hold image data; I'm using a string to represent a link to an image for clarity.
static void Main(string[] args)
{
using (ContactsEntities entities = new ContactsEntities())
{
entities.Persons.Add(new Person() { FirstName = "Jane", LastName = "Doe", Photo = new Photo() { PhotoLink = "/images/jane.jpg" } });
entities.Persons.Add(new Person() { FirstName = "John", LastName = "Doe" }); // no photo
entities.Persons.Add(new Person() { FirstName = "Joe", LastName = "Smith", Photo = new Photo() { PhotoLink = "/images/joe.jpg", ThumnbnailLink = "/images/thumbs/joe.jpg" } });
// note that the following is not allowed based on the defined RI rules - will fail on call to SaveChanges:
// entities.Photos.Add(new Photo() { PhotoLink = "/images/as.jpg" });
entities.SaveChanges();
foreach (Person person in entities.Persons)
{
Console.WriteLine("{0} {1} {2}", person.FirstName, person.LastName, person.Photo == null ? "missing photo" : person.Photo.PhotoLink);
}
}
Console.WriteLine("Press Enter to exit...");
Console.ReadLine();
}
}
public partial class ContactsEntities : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// a Person may have at most one Photo
modelBuilder.Entity<Person>().HasOptional<Photo>(p => p.Photo);
// a Photo is dependant on a Person (non-nullable FK constraint)
modelBuilder.Entity<Photo>().HasRequired<Person>(p => p.Person);
base.OnModelCreating(modelBuilder);
}
public DbSet<Photo> Photos { get; set; }
public DbSet<Person> Persons { get; set; }
}
[Table("Photos")]
public partial class Photo
{
[Key]
public int PhotoID { get; set; }
[Required]
public string PhotoLink { get; set; }
public string ThumnbnailLink { get; set; }
public virtual Person Person { get; set; }
}
[Table("Persons")]
public partial class Person
{
[Key]
public int PersonID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
public virtual Photo Photo { get; set; }
}