EF Code First Multiple Tables to single entity - entity-framework

I'm just starting out with Entity Framework and I seem to be misunderstanding something. Basically I've got a database already setup. Let's say the following are my tables.
**Employees**
EmployeeId
CubeId (FK to Cubes table)
NameId (FK to Name table)
**Cubes**
CubeId
CubeName
**Person**
NameId
FirstName
LastName
I want to be able to write something like this: SELECT EmployeeId, CubeId, CubeName, FirstName, LastName FROM Employees LEFT OUTER JOIN Cubes LEFT OUTER JOIN Person. So it would return all of the Employees. Basically, in EF Code First do you have to create a class for EVERY table? If not, how do you create a LEFT OUTER Join equivalent? All of the examples I've found use navigational properties to go from table to table (i.e. class to class).

Models:
public class Employee
{
[Key]
public int EmployeeId {get;set;}
public int CubeId {get;set;}
[ForeignKey("Cube")]
public int NameId {get;set;}
[ForeignKey("Name")]
public virtual Cube Cube {get;set;}
public virtual Name Name {get;set;}
}
public class Cube
{
[Key]
public int CubeId {get;set;}
public string CubeName {get;set;}
}
public class Name
{
[Key]
public int NameId {get;set}
public string FirstName {get;set;}
public string LastName {get;set;}
}
Your context:
public class YourContext:DbContext
{
public DbSet<Name> Names {get;set;}
public DbSet<Cube> Cubes {get;set;}
public DbSet<Employee> Employees {get;set;}
}
Your query:
YourContext db = new YourContext();
var query = db.Employees.Where(x => x.EmployeeId == id).Select(x => new
{
EmployeeId = x.EmployeeId,
CubeId = x.Cube.CubeId,
CubeName = x.Cube.CubeName,
FirstName = x.Name.FirstName,
LastName = x.Name.LastName
}).FirstOrDefault();
This will locate first employee that has some id (or return null if there's none), and then create a type that has all the properties you mentioned. If you need last name, you access it with:
string lastName = query.LastName;

Related

Remove table name prefix in EF code first foreign key table column

I have two Entity
Room{
[Key]
public int RoomID {get;set;}
public String RoomName {get;set;}
public List<Member> ListMember {get;set;}
}
Member {
[Key]
public int MemberID {get;set;}
public String MemberName {get;set;}
public Room Room {get;set;}
}
when generate the database, table Member look like:
Member(
MemberID int,
MemberName nvarchar.
Room_RoomID int //references to Room(RoomID)
)
I want the foreign key column have name RoomID (same as Room's original name) instead of (Room_RoomID) .
How can I do that?
You have several options to do that:
Declare that RoomId FK property in the Member entity and use
the ForeignKey data annotation:
public classMember {
[Key]
public int MemberID {get;set;}
public String MemberName {get;set;}
[ForeignKey("Room")]
public int RoomID {get;set;}
public Room Room {get;set;}
}
Code First convention creates a column name same as the property name.
If you don't want to declare the RoomId FK property in your Member entity, you can override OnModelCreating method in your context class to
configure your relationship and specify the FK name using the
MapKey method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Member>().HasRequired(m=>m.Room).WithMany(r=>r.ListMember).Map(a => a.MapKey("RoomId"))
}
Now, in case that you declare the RoomId FK property but you want to change the name of that column in your Members table , you can use the Column data annotation.

Entity Framework - Eager loading, all properties to list

I have a simple project in which i have the following model.
Customer 1--->N Addresses N<----1 City N<----1 Country
^
N|
|
AddressTypes 1-------+
Here is my code:
public partial class Customer {
public Customer() {
this.Address = new HashSet<Address>();
}
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public System.DateTime Birthday {get;set;}
public virtual ICollection<Address> Address {get;set;}
}
public partial class Address {
public int Id {get;set;}
public string Street {get;set;}
public string Area {get;set;}
public string Post {get;set;}
public bool isDeleted {get;set;}
public virtual Customer Customer {get;set;}
public virtual City City {get;set;}
public virtual AddressType AddressType {get;set;}
}
public partial class AddressType {
public AddressType() {
this.Address = new HashSet<Address>();
}
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<Address> Address {get;set;}
}
public partial class Country {
public Country() {
this.City = new HashSet<City>();
}
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<City> City {get;set;}
}
public partial class City {
public City() {
this.Address = new HashSet<Address>();
}
public int Id {get;set;}
public string Name {get;set;}
public virtual ICollection<Address> Address {get;set;}
public virtual Country Country {get;set;}
}
public partial class MyModelContext : DbContext {
public MyModelContext()
: base("name=MyModelContext") {
this.Configuration.LazyLoadingEnabled = true;
this.Configuration.ProxyCreationEnabled = false;
}
public virtual DbSet<Country> Countries {get;set;}
public virtual DbSet<City> Cities {get;set;}
public virtual DbSet<AddressType> AddressTypes {get;set;}
public virtual DbSet<Address> Addresses {get;set;}
public virtual DbSet<Customer> Customers {get;set;}
}
I want to return a list of customers. At first i tried to do a simple Customers.ToList() but i was getting an exception during serialization and i read that this was caused by cyclical references. So i added
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = false;
and then i was able to get the customers but without the addresses. I tried doing:
public List<Customer> getCustomers() {
MyModelContext db = new MyModelContext();
return db.Customers.Include("Address").ToList();
}
but i don't know how to retrieve ALL the properties. I want to get in the list every customer and his addresses including the city, country, addresstype of each address. How can i do it?
You have couple of options:
1. Use DTOs (Data Transfer Objects).
2. Explicitly ignore the problematic property that contains the circular references to the parent object by applying the below Attributes:
// in Address entity
[IgnoreDataMember]
[XmlIgnore]
[NonSerialized]
public Customer Custom { get; set; }
Also in AddressType.Address, City.Address, and Country.City.
3. Project your entities into anonymous objects and exclude the pr:
db.Customers.Select(c => new
{
c.Id,
c.FirstName,
c.LastName,
c.Birthday,
Address = c.Address.Select<Address, object>(a => new
{
a.Id,
AddressType = new
{
a.AddressType.Id,
a.AddressType.Name
},
a.Area,
City = new
{
a.City.Id,
Country = new
{
a.City.Country.Id,
a.City.Country.Name
},
a.City.Name,
},
a.Post,
a.Street,
a.isDeleted
}),
});
You'll have to turn LazyLoadingEnabled and ProxyCreationEnabled back on in order for it to work (or use Include).
(As a side note, i don't really understand why you need this circular references at all, what benefit do you get from AddressType.Address?)
I solved it this way:
public List<Customer> getCustomers() {
var customers = db.CustomerSet.Include("Address")
.Include("Address.AddressType")
.Include("Address.City")
.Include("Address.City.Country")
.ToList();
return customers;
}
i don't really like that i have to explicitly write all the properties of the customer and there is not a generic way of doing what i want but it works.

Entity Framework, Unneeded Foreign key

I'm using EF Code first.
I created two classes. For simplicity, imagine that I have a User table (class) and a FileAttachment table. I want to use the FileAttachment table with many other classes, so that any part of the application that requires having a FileAttachment can reuse that table. The problem is that when EF generates the schema, it creates a Foreign Key in the FileAttachment table back to User table. Is there a way to disable that?
Thanks
You need to build an intermediate class.
public class UserDocument
{
public int Id {get;set;}
public int UserId {get;set;}
public virtual User User {get;set;}
public int FileAttachmentId {get;set;}
public virtual FileAttachment FileAttachment {get;set;}
}
So your user class can now have:
public virtual ICollection<UserDocument> Documents {get;set;}
And in this case, FileAttachment class will not have reference to User.
If you want now to build some other document type, just implement another intermediate type, i.e. imagine you want to have CustomerDocument:
public class CustomerDocument
{
public int Id {get;set;}
public int CustomerId {get;set;}
public virtual Customer Customer {get;set;}
public int FileAttachmentId {get;set;}
public virtual FileAttachment FileAttachment {get;set;}
}
And then your hypothetical Customer class would have:
public virtual ICollection<CustomerDocument> Documents {get;set;}

Entity Framework Code First: Entity Splitting

Is it possible to map the following scenario?
Data Tables
Students
+ ID: int PK
+ Name: varchar(200)
Classes
+ ID: int PK
+ StudentID: FK
+ CourseID: FK
+ EnrollmentDate: DateTime
Courses
+ ID: int PK
+ Name: varchar(200)
I would like to map the tables to entities below.
public class Student
{
[Key]
public int ID {get;set;}
public string Name {get;set;}
public virtual ICollection<Class> Classes {get;set;}
}
public class Class
{
[Key]
public int ID {get;set;}
public Student Student {get;set;}
public DateTime EnrollmentDate {get;set;}
public string Name {get;set;} // this comes from the Courses data table
}
This should be how to establish the FK relationships you require:
public class Student
{
[Key]
public int StudentId {get;set;}
public string Name {get;set;}
}
public class Class
{
[Key]
public int ClassId {get;set;}
public DateTime EnrollmentDate {get;set;}
//foreign keys
public int CourseId {get;set;}
public string StudentId {get;set;}
//virtual constraint to link to referenced tables
public virtual Course Course {get;set;}
public virtual Student Student {get;set;}
}
public class Course
{
[Key]
public int CourseId {get;set;}
public string CourseName {get;set;}
}

Entity Framework 4 code-only reference column name

I created classes:
public class Country
{
public long CountryId {get;set;}
public string CountryName {get;set;}
}
public class Profile
{
public long ProfileId {get;set;}
public string ProfileName {get;set;}
public Country Country {get;set;}
}
and configuration for Profile:
public class ProfileConfiguration : EntityConfiguration<Profile>
{
public IlluminatiCoreProfileConfiguration()
{
Relation(p => p.Country);
}
}
Then I create context and run context.CreateDatabase(). New database contains table Profiles with column Country_CountryId. How can I write configuration for changing column name to "CountryId"?
Thanks.
In your POCO for Profile:
public class Profile
{
public long ProfileId {get;set;}
public string ProfileName {get;set;}
[ForeignKey("CountryId")]
public Country Country {get;set;}
}
In your POCO for Country
[Table("Country")]
public class Country
{
[Column(Name = "CountryId")]
public int CountryId {get;set;}
}
This will over write the brain dead Object_Property mapping that EF by default creates. You can specify this on any table / property to override the actual DB column naming conventions.
EDIT:
I guess the namespace for those annotations would be helpful:
using System.ComponentModel.DataAnnotations;