Configuring a Relationship Where Both Ends Are Required (One-to-One) - entity-framework

the sample code on http://msdn.microsoft.com/en-US/data/jj591620#RequiredToRequired is it even correct? the code is asking for OfficeAssignment prop on the Instructor class. it will not resolve for obvious reasons. what is the correct way of having a one-to-one relationship on ef now?
// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
.HasKey(t => t.InstructorID);
modelBuilder.Entity<Instructor>()
.HasRequired(t => t.OfficeAssignment)
.WithRequiredPrincipal(t => t.Instructor);
public class OfficeAssignment
{
// Specifying InstructorID as a primary
[Key()]
public Int32 InstructorID { get; set; }
public string Location { get; set; }
// When the Entity Framework sees Timestamp attribute
// it configures ConcurrencyCheck and DatabaseGeneratedPattern=Computed.
[Timestamp]
public Byte[] Timestamp { get; set; }
// Navigation property
public virtual Instructor Instructor { get; set; }
}
public class Instructor
{
public Instructor()
{
this.Courses = new List<Course>();
}
// Primary key
public int InstructorID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public System.DateTime HireDate { get; set; }
// Navigation properties
public virtual ICollection<Course> Courses { get; private set; }
}

There is mistake around the Local/office nav property. A few deliberate renames to clarify
Perhaps this....
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace one2one
{
class Program
{
static void Main(string[] args)
{
var context = new Demo();
var instructor = new Instructor();
instructor.FirstName = "Big";
instructor.LastName = "Willi";
context.Set<Instructor>().Add(instructor);
var office = new OfficeAssignment();
office.Location = "is this where the demo broke down ? See POCO ";
office.InstructorUsingThisOffice = instructor;
context.Set<OfficeAssignment>().Add(office);
context.SaveChanges();
}
}
public class OfficeAssignment
{
// Specifying InstructorID as a primary
public Int32 InstructorID { get; set; }
public string Location { get; set; }
// Navigation property
public virtual Instructor InstructorUsingThisOffice { get; set; }
}
public class Instructor
{
// Primary key
public int InstructorID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
//navigation
//missing
public virtual OfficeAssignment TheofficeToUse { get; set; }
}
public class Demo : DbContext
{
DbSet<OfficeAssignment> officeAssignments { get; set; }
DbSet<Instructor> Instructors { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
.HasKey(t => t.InstructorID);
modelBuilder.Entity<Instructor>()
.HasRequired(t => t.TheofficeToUse)
.WithRequiredPrincipal(d => d.InstructorUsingThisOffice); //current entity is principal, the navigation back.
// and we share the same key... MUST with EF 1:1 foreign key
}
}
}

Related

EFCore Generic Repository and UnitOfWork Design Pattern

when im trying to create new data and save it, im getting error at the
public int Complete()
{
return _context.SaveChanges();
}
and error is saying me that:
The value of 'Agency.ID' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known. .
i have a Base class like that:
public class Base
{
protected Base()
{
CreatedDate = DateTime.Now;
IsDeleted = false;
ModifiedDate = null;
}
public int ID { get; set; }
public int? CreatedUserId { get; set; }
public int? ModifiedUserId { get; set; }
public string CreatedUserType { get; set; }
public string ModifiedUserType { get; set; }
public DateTime? CreatedDate { get; set; }
public DateTime? ModifiedDate { get; set; }
public bool? IsActive { get; set; }
public bool? IsDeleted { get; set; }
}
i have a Agency class like that :
public class Agency : Base
{
public Agency()
{
AgencyIsComplated = false;
}
[Required, StringLength(255)]
public string AgencyName { get; set; }
[Required, StringLength(255)]
public string AgencyPhoto { get; set; }
[Required, StringLength(255)]
public string AgencyEMail { get; set; }
[Required, StringLength(13)]
public string AgencyPhone { get; set; }
[StringLength(13)]
public string AgencyBPhone { get; set; }
[StringLength(255)]
public string AgencyInfo { get; set; }
[Required, StringLength(255)]
public string AgencyTitle { get; set; }
[Required, StringLength(255)]
public string AgencyLink { get; set; }
public int AgencyExportArea { get; set; } // Join table ile yapılacak,ayrı bir tabloda tutulacak
[Required, StringLength(255)]
public string AgencyInstagram { get; set; }
public string AgencyTwitter { get; set; }
public string AgencyFacebook { get; set; }
public string AgencyLinkedin { get; set; }
public string AgencyYoutube { get; set; }
public bool AgencyIsComplated { get; set; }
[ForeignKey("CompanyID")]
public Company Company { get; set; }
[ForeignKey("LogID")]
public Log Log { get; set; }
public virtual ICollection<AgencyCompany> AgencyCompanies { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<Log> Logs { get; set; }
}
public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
{
public void Configure(EntityTypeBuilder<Agency> builder)
{
builder.HasKey(agency => agency.ID);
builder.HasMany(a => a.Logs)
.WithOne(a => a.Agency)
.HasForeignKey(a=>a.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(us => us.Users)
.WithOne(us => us.Agency)
.HasForeignKey(au=>au.ID)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(ac => ac.AgencyCompanies)
.WithOne(ac => ac.Agency)
.OnDelete(DeleteBehavior.Restrict);
}
}
and i have got a UnitOfWork like that:
public class UnitOfWork : IUnitOfWork
{
private TradeTurkDBContext _context;
public UnitOfWork(TradeTurkDBContext context)
{
_context = context;
RepositoryAgency = new RepositoryAgency(_context);
}
public IRepository Repository { get; private set; }
public IRepositoryAgency RepositoryAgency { get; private set; }
public int Complete()
{
return _context.SaveChanges();
}
public void Dispose()
{
_context.Dispose();
}
}
im inheriting that ID on my Base Model.
the problem is getting solved when im not defining ID in the base model but i allready set up my mapping on it.
so how can i solve that error without using AgencyID in the Agency model ?
The foreign key is in the details (or child) table. Therefore, e.g. a user, should have an AgencyId as foreign key.
builder.Entity<User>()
.HasOne(u => u.Agency)
.WithMany(a => a.Users)
.HasForeignKey(u => u.AgencyId)
.OnDelete(DeleteBehavior.Restrict);
This key automatically points to the primary key of the master (or parent) table.
User.ID is a primary key. User.AgencyId is a foreign key which (automatically) relates to the primary key Agency.ID.
E.g. see: Configure One-to-Many Relationships using Fluent API in Entity Framework Core

EF6 Code First - Multiple one-to-many and same entity

I have an entity model that contains multiple definitions to another entity. I can get one definition to work, but not both.
public class Inspection : Entity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int InspectionId { get; set; }
[ForeignKey("Report")]
public int ReportId { get; set; }
public virtual Report Report { get; set; }
....
public virtual ICollection<ResidentialDescriptionItem> ResidentialDescriptionItems { get; set; }
public virtual ICollection<ResidentialDescriptionItem> ResidentialOtherDescriptionItems { get; set; }
}
public class ResidentialDescriptionItem : Entity<int>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ResidentialDescriptionItemId { get; set; }
public int InspectionId { get; set; }
[ForeignKey("InspectionId")]
public virtual Inspection Inspection { get; set; }
//public int Inspection1Id { get; set; }
//[ForeignKey("Inspection1Id")]
//public virtual Inspection Inspection1 { get; set; }
}
I've made numerous attempts with that second index and received just as many different errors. The above configuration results in
Unable to determine the principal end of the
'MySolution.EntityFramework.ResidentialDescriptionItem_Inspection'
relationship. Multiple added entities may have the same primary key.
I would like to maintain a full configuration with navigation on both sides. How do I do this using Code First and Annotations?
I don't think it is possible to implement such complex relationship with annotations, but here is a demo, how you would need to override your DbContext.OnModelCreating
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
namespace ConsoleApp3
{
public class Parent
{
[Key]
public int Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
public virtual ICollection<Child> OtherChildren { get; set; }
}
public class Child
{
[Key]
public int Id { get; set; }
[ForeignKey("Parent")]
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Parent Parent { get; set; }
[ForeignKey("OtherParent")]
public int? OtherParentId { get; set; }
[ForeignKey("OtherParentId")]
public virtual Parent OtherParent { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
public DbSet<Parent> Parents { get; set; }
public DbSet<Child> Children { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Parent>()
.HasMany(x => x.Children)
.WithOptional(x => x.Parent);
modelBuilder.Entity<Parent>()
.HasMany(x => x.OtherChildren)
.WithOptional(x => x.OtherParent);
}
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyDbContext>());
var ctx = new MyDbContext("Data Source=DESKTOP-5PVJ0I5;Database=test1;Integrated Security=true");
var parent = ctx.Parents.Add(new Parent());
ctx.Children.Add(new Child()
{
OtherParent = parent
});
ctx.Children.Add(new Child()
{
Parent = parent
});
ctx.SaveChanges();
parent = ctx.Parents
.Include(x => x.Children)
.Include(x => x.OtherChildren)
.FirstOrDefault();
}
}
}

How to insert data into a table with composite key from Multiple Tables in ASP.NET MVC

Answer to this question is found at here
Having three tables:
Database diagram is here
Book class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class Books
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Books()
{
UserBookComments = new HashSet<UserBookComments>();
}
[Key]
public int BookID { get; set; }
[Required]
[StringLength(255)]
public string Title { get; set; }
[Required]
[StringLength(255)]
public string Category { get; set; }
[Column(TypeName = "date")]
public DateTime PublishDate { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserBookComments> UserBookComments { get; set; }
}
User class:
public partial class Users
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Users()
{
UserBookComments = new HashSet<UserBookComments>();
}
[Key]
public int UserID { get; set; }
[Required]
[StringLength(255)]
public string UserName { get; set; }
[Required]
[StringLength(255)]
public string Password { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<UserBookComments> UserBookComments { get; set; }
}
And the UserBookComments class:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.Spatial;
public partial class UserBookComments
{
[Key]
[Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int UserID { get; set; }
[Key]
[Column(Order = 1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BookID { get; set; }
public int? Comments { get; set; }
public virtual Bookss Bookss { get; set; }
public virtual Users Users { get; set; }
}
The table "Books" is an already saved database. Each user can comment for each book and I want a view model that holds all the data from books with their comments.
The primary key on UserBookComment would be composite, on UserID and BookID.
I used EF Code First and my DBModel context class looks so:
using System.Data.Entity;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
public partial class DbModel : DbContext
{
public DbModel()
: base("name=DbModel")
{
}
public virtual DbSet<Books> Books { get; set; }
public virtual DbSet<UserBookComments> UserBookComments { get; set; }
public virtual DbSet<Users> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Books>()
.Property(e => e.Category)
.IsUnicode(false);
modelBuilder.Entity<Books>()
.HasMany(e => e.UserBookComments)
.WithRequired(e => e.Books)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Users>()
.HasMany(e => e.UserBookComments)
.WithRequired(e => e.Users)
.WillCascadeOnDelete(false);
}
}
I wonder how to save comments and display whole list of [title, category, publish date and comments] using a ViewModel class?
As you asked in the comments, I have provided the way to insert a record into the UserBookComment table by adding a method into the BookEntities class.
public partial class BooksEntities : DbContext
{
public virtual DbSet<Books> Books { get; set; }
public virtual DbSet<UserBookComment> UserBookComments { get; set; }
public virtual DbSet<Users> Users { get; set; }
public void AddComment(int userId, int bookId, string comment)
{
var userBookComment = new UserBookComment()
{
UserId = userId,
BookId = bookId,
Comment = comment
};
this.AddComment(userBookComment);
}
public void AddComment(UserBookComment userBookComment)
{
this.UserBookComment.Add(userBookComment);
this.UserBookComment.SaveChanges();
}
}
I assumed based on your provided information that your UserBookComment class looked like this
public class UserBookComment
{
public int UserId { get; set; }
public int BookId { get; set; }
public string Comment { get; set; }
}
Looks like you are using entity framework. To create a composite key, just at the Key attribute on both properties. To control the key order use the column atribute. Referencing should be fixed automaticly using the names in the model, or try googling on entity framework foreign key. I'm sorry I don't have the link right now.
For the viewmodel, just don't foget to use include in the statement.

Error in many-to-many relationship using Fluent API in Entity Framework 6 one model is self referencing

Category model is self referencing
public class Category
{
[Key]
public int CategoryID { get; set; }
public string Name { get; set; }
public int? ParentID { get; set; }
public Category Cat { get; set; }
public ICollection<Category> Categories { get; set; }
public ICollection<BusinessDetail> BDetails { get; set; }
}
and BusinessDetail is like
public class BusinessDetail
{
[Key]
public int ID { get; set; }
[Required]
[Display(Name="Business Name")]
public string BusinessName { get; set; }
public string Address { get; set; }
[Display(Name="Contact")]
public string contactDetail { get; set; }
// public int CategoryID { get; set; }
// public Category Category { get; set; }
public int ? LocationID { get; set; }
public Location Location { get; set; }
[Display(Name="Website Address")]
public string Website_Address { get; set; }
[Display(Name="Is Verified")]
public bool Is_verified { get; set; }
[Required]
[Display(Name="Added By")]
public string Added_By { get; set; }
[Required]
[Display(Name="Added Date")]
[DataType(DataType.DateTime)]
public DateTime Added_Date { get; set; }
[Display(Name="Is Featured")]
public bool Is_Featured { get; set; }
public string Latitude { get; set; }
public string VerifiedBy { get; set; }
public string Longitude { get; set; }
public ICollection<Category> Categories { get; set; }
}
When creating a many-to-many relationship using Fluent API
modelBuilder.Entity<BusinessDetail>()
.HasMany(c => c.Categories).WithMany(i => i.BDetails)
.Map(t => t.MapLeftKey("ID")
.MapRightKey("CategoryID")
.ToTable("BusinessCategories"));
I get this error
There are no primary or candidate keys in the referenced table
'dbo.BusinessDetails' that match the referencing column list in the
foreign key 'FK_dbo.BusinessCategories_dbo.BusinessDetails_ID'.
I need help on this error.
I will try to work out your exact example, but the code below works without any configuration:
EDIT:
I added in the code from OnModelCreating and changed the property names to those in your exampe, but it all keeps working. You do realize though, that the ParentId property is not seen as the foreign key for a parent Category, but that EF will create a Cat_CategoryId foreign key for you?
I advise to start from scratch using my code and work step by step towards the existing code.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Data.Entity;
public class CategoryContext : DbContext
{
public DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Fill in later.
}
}
public class Category
{
public Category()
{
Children = new List<Category>();
Details = new List<BussinesDetail>();
}
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
public virtual Category Parent { get; set; }
public virtual ICollection<Category> Children { get; set; }
public virtual ICollection<BussinesDetail> Details { get; set; }
}
public class BussinesDetail
{
public int Id { get; set; }
public string BussinesName { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
static class Module1
{
public static void Main()
{
using (context = new CategoryContext()) {
var newCat = context.Categories.Add(new Category { Name = "CatOne" });
context.SaveChanges();
newCat = context.Categories.Single;
Console.WriteLine(newCat.Name);
Console.ReadLine();
}
}
}

Entity Framework Code First Many to Many Setup For Existing Tables

I have the following tables Essence, EssenseSet, and Essense2EssenceSet
Essense2EssenceSet is the linking table that creates the M:M relationship.
I've been unable to get the M:M relationship working though in EF code first though.
Here's my code:
[Table("Essence", Schema = "Com")]
public class Essence
{
public int EssenceID { get; set; }
public string Name { get; set; }
public int EssenceTypeID { get; set; }
public string DescLong { get; set; }
public string DescShort { get; set; }
public virtual ICollection<EssenceSet> EssenceSets { get; set; }
public virtual EssenceType EssenceType { get; set; }
}
[Table("EssenceSet", Schema = "Com")]
public class EssenceSet
{
public int EssenceSetID { get; set; }
public int EssenceMakerID { get; set; }
public string Name { get; set; }
public string DescLong { get; set; }
public string DescShort { get; set; }
public virtual ICollection<Essence> Essences { get; set; }
}
[Table("Essence2EssenceSet", Schema = "Com")]
public class Essence2EssenceSet
{
//(PK / FK)
[Key] [Column(Order = 0)] [ForeignKey("Essence")] public int EssenceID { get; set; }
[Key] [Column(Order = 1)] [ForeignKey("EssenceSet")] public int EssenceSetID { get; set; }
//Navigation
public virtual Essence Essence { get; set; }
public virtual EssenceSet EssenceSet { get; set; }
}
public class EssenceContext : DbContext
{
public DbSet<Essence> Essences { get; set; }
public DbSet<EssenceSet> EssenceSets { get; set; }
public DbSet<Essence2EssenceSet> Essence2EssenceSets { get; set; }
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<Essence>()
.HasMany(e => e.EssenceSets)
.WithMany(set => set.Essences)
.Map(mc =>
{
mc.ToTable("Essence2EssenceSet");
mc.MapLeftKey("EssenceID");
mc.MapRightKey("EssenceSetID");
});
}
}
This is the code I'm trying to run:
Essence e = new Essence();
e.EssenceTypeID = (int)(double)dr[1];
e.Name = dr[2].ToString();
e.DescLong = dr[3].ToString();
//Get Essence Set
int setID = (int)(double)dr[0];
var set = ctx.EssenceSets.Find(setID);
e.EssenceSets = new HashSet<EssenceSet>();
e.EssenceSets.Add(set);
ctx.Essences.Add(e);
ctx.SaveChanges();
And here's the error:
An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception.
I'm not able to find the problem. I'd greatly appreciate help setting this up right.
Thanks!
Remove your Essence2EssenceSet model class. If junction table contains only keys of related entities participating in many-to-many relations it is not needed to map it as entity. Also make sure that your fluent mapping of many-to-many relations specifies schema for table:
mb.Entity<Essence>()
.HasMany(e => e.EssenceSets)
.WithMany(set => set.Essences)
.Map(mc =>
{
mc.ToTable("Essence2EssenceSet", "Com");
mc.MapLeftKey("EssenceID");
mc.MapRightKey("EssenceSetID");
});