I'm new to ORM tools and I want to do relationships between tables only with naming convention. For example if I have classes like below;
public class City
{
public int Id;
public string Name;
}
public class District
{
public int Id;
public string Name;
public City City;
}
I want to map these classes in my database like this.
City
Id int,
Name nvarchar(100)
District
Id int,
Name nvarchar(100),
CityId int
I don't want to use foreign keys and when I put any class as a property in another class I want to migrate these property as "ClassNameId". Any solution for this ?
Your design for relationship is not correct to use EF.
the correct relationship is
public class City
{
public int Id;
public string Name;
public virtual ICollection<District> Districts;
}
public class District
{
public int Id;
public string Name;
public int CityId;
public virtual City City;
}
and in entity configuration you need to make in city definition on your EntityTypeConfiguration :
public DistrictConfiguration()
{
HasKey(a => a.Id);
HasRequired(a => a.City)
.WithMany(a => a.Districts)
.HasForeignKey(a => a.CityId);
ToTable("District");
}
Related
I am using EF version 6.1 and have a mapping problem:
class BasePoco
{
public Guid Id{get;set;}
}
class Student : BasePoco
{
public string Name;
}
public class UserBase : BasePoco
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public string Photo { get; set; }
}
public class UserDetail : UserBase
{
public string MobileNumber { get; set; }
public string EmailID { get; set; }
}
public Enum UserType
{
Student = 1,
User=2
}
the Attendance class
public class Attendance
{
public class UserId {get;set;} // Can be either student or user
public UserType UserType {get;set;}
}
I need to mark attendance for Student as well as User in the same table.
The UserType would determine whether the Id is of a student or User and the primary key would be a combination of UserType and Id.
How can I accomplish this using EF code first approach.
Sorry you cant use multiple type over single property. You do understand, because EF run over metadata. Which use EF know metadata from model class. This is a problem. Attendance table foregin key is multiple table referance and Attendance model contains both model. You should create logical layer for check UserType and access correct model. For example
public class Attendance
{
public UserType userType {get;set;}
public Guid? UserId {get;set;}
public virtual User user {get;set;}
public Guid? StudentId {get;set;}
public virtual Student student {get;set;}
}
now layer class
public class AttendanceUserLayer
{
public static object GetUser(Attendance attendance) {
if (attendance.userType == UserType.User) {
return attendance.User;
} else {
return attendance.Student;
}
}
how to use
Attendance attendance = context.Attendance.FirstOrDefault();
var userOrStudent = AttendanceUserLayer.GetUser(attendance);
if you cannot use the type of object result, write interface both class and set return type that interface.
I have a project class which contains:
int ProjectID;
string ProjectName;
List<Item> Items;
I have a item class which contains:
int ItemID;
int? ParentID; // ID of Parent Item
string ItemName;
List<Item> Items;
I would expect my Items Table to hold the following columns:
ItemID, ParentID, ItemName
But for some reason it's adding another column ItemItemID.
I have tried several things with fluent API. (WithOptional, MapKey etc...) But I can't find a thing that is working for me. I think the problem is that the ParentID is not seen as the relation for the Item.
Please show me a solution, cause I'm already stuck for hours...
Entity Framework could not infer that the ParentID property is actually the foreign key to the parent Item object in the same table, so it decided to create a special column for that in the database. You have to tell it that ParentID is actually a foreign key by using the ForeignKey attribute.
Change the definition of the Item class to something like this:
public class Item
{
public Item()
{
Items = new HashSet<Item>();
}
public int ItemID { get; set; }
[ForeignKey("Parent")]
public int? ParentID { get; set; } // ID of Parent Item
public string ItemName { get; set; }
public virtual ICollection<Item> Items { get; set; }
public virtual Item Parent { get; set; }
}
Notice how I added a public virtual Item Parent property because the ForeignKey attribute needs to point to the property that presents the parent entity.
If you prefer to use the fluent API, then remove the ForeignKey attribute, and override the OnModelCreating method on the context class to something like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder
.Entity<Item>()
.HasMany(e => e.Items)
.WithOptional(e => e.Parent)
.HasForeignKey(e => e.ParentID);
}
I'm working with the EF code first approach and want to add a link (map) table. I am working off the below example and get the following error:
System.Data.Entity.Edm.EdmEntityType: : EntityType 'EmployeeDepartmentLink' has no key defined. Define the key for this EntityType.
Problem is I dont want a key on this table it just maps the two tables together:
public class Employee
{
[Key()]
public int EmployeeID;
public string Name;
}
public class Department
{
[Key()]
public int DepartmentID;
public string Name;
}
public class EmployeeDepartmentLink
{
public int EmployeeID;
public int DepartmentID;
}
I have tried a variety of things like adding the "[Key()]" attribute but it doesn't make sense for it to be used, and which field do I add it to? I am wondering if this sort of table model is even supported?
You are trying to make a "Many to Many" mapping.
To perform this, write this code:
public class Employee
{
[Key]
public int EmployeeId;
public string Name;
public List<Department> Departments { get; set; }
public Employee()
{
this.Departments = new List<Department>();
}
}
public class Department
{
[Key]
public int DepartmentId;
public string Name;
public List<Employee> Employees { get; set; }
public Department()
{
this.Employees = new List<Employee>();
}
}
then, in your DbContext:
public class YourContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
public DbSet<Department> Departments { get; set; }
public YourContext() : base("MyDb")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Department>().
HasMany(c => c.Employees).
WithMany(p => p.Departments).
Map(
m =>
{
m.MapLeftKey("DepartmentId");
m.MapRightKey("EmployeeId");
m.ToTable("DepartmentEmployees");
});
}
}
For M:M relationship you have to create your join (link) class is as below.
public class EmployeeDepartmentLink
{
[Key, Column(Order = 0)]
public int EmployeeID;
[Key, Column(Order = 1)]
public int DepartmentID;
}
For more information check Create code first, many to many
I hope this will help to you.
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;
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;