update foreign key using entity framework - entity-framework

i am trying to update foreign key in a table named(Friendship).The foreign key is of the table named(FriendshipStatus) the problem is that all the values are updated except the foreign key. I m using code first approach.
Friendship Class
public class Friendship
{
public int Id { get; set; }
public User UserOne { get; set; }
public User UserTwo { get; set; }
public FriendshipStatus Status { get; set; }
public User ReqSB { get; set; }
public RelationType RelationType { get; set; }
public Relationship Relationship { get; set; }
public DateTime FriendshipDate { get; set; }
}
FriendshipStatus class
public class FriendshipStatus
{
public int Id { get; set; }
public string Name { get; set; }
}
Here is the code for update
using (context)
{
Friendship f = getFrienshipRecord(u1, u2); // get single record from db which is to be updated
if (f != null)
{
Friendship ff = new Friendship();
ff.Status = new FriendshipStatus() { Id = 2}; //actually wants to update this this field
ff.Id = f.Id;
ff.FriendshipDate = DateTime.Now;
context.Entry(ff).State = EntityState.Modified;
context.SaveChanges();
}
}
The above code changes datetime but it does not change foreign key.

This is the technique I use for updates that include a child. First, I like to expose the Foreign Key as part of the parent. If you name it FriendshipStatusId, EF will make the association automatically or you can add an annotation or fluent code if preferred:
public class Friendship
{
public int Id { get; set; }
public User UserOne { get; set; }
public User UserTwo { get; set; }
public int? FriendshipStatusId { get; set; } // optional FK
public FriendshipStatus Status { get; set; }
public User ReqSB { get; set; }
public RelationType RelationType { get; set; }
public Relationship Relationship { get; set; }
public DateTime FriendshipDate { get; set; }
}
Now you can do your update by simply fetching the entity (which puts it under tracking) and updating the FK:
using (context)
{
Friendship f = getFrienshipRecord(u1, u2); // get single record from db which is to be updated
if (f != null)
{
f.FriendshipDate = DateTime.Now;
f.FriendshipStatusId = 2;
context.SaveChanges();
}
}
Note that if you add the FK you may need to do a migration or regenerate your database because the EF default might be something like FriendshipStatus_Id.

Related

How to join two model and display them in view in mvc 3.0 EF 5

I have two tables which have primary and foriegn key concept. I want to get the combined data on behalf of those keys. i don't know how to bind both the table into single model and display it into view.
Model
public class TVSerialModel
{
public Int32 Serial_ID { get; set; } // primary key
public string Serial_Name { get; set; }
public int? Release_Year { get; set; }
}
public class TVSerialEpisodeModel
{
public Int64 Video_ID { get; set; }
public Int32 Serial_ID { get; set; }// foriegn key
public string Episode_Name { get; set; }
public string Description { get; set; }
public DateTime Uploaded_Time { get; set; }
}
public class TVSerial_Episode_VM
{
public IEnumerable<TVSerialEpisodeModel> tvserialEpisode { get; set; }
public IEnumerable<TVSerialModel> Tvserial { get; set; }
}
Controller
public ActionResult NewEpisodeReleased()
{
cDBContext tvContext = new cDBContext();
TVSerial_Episode_VM tves=new TVSerial_Episode_VM();
tves= tvContext.dbTvSerialEpisodes.
Join(tvContext.dbTvSerials, p => p.Serial_ID, r => r.Serial_ID,(p, r) => new { p, r }).
Select(o => new TVSerial_Episode_VM
{ ****what should i write here to get all columns from both table**** }).
Take(9).ToList();
return View(tves);
}
Expected Result
If TVSerialEpisode has a property TVSerial, you can just dot through your foreign keys.
cDBContext.dbTvSerialEpisode
.Select(t =>
new {
t.TVSerial.Serial_ID,
t.TVSerial.Serial_Name,
t.Episode_Name
})
.Take(9)
.ToList();
You need to improve little bit the models you used with EF. You must include the reference object in model.
Like this
public virtual TVSerialModel TVSerialModel { get; set; }
in main table. This way you can select referred table too.
EF Include
public ActionResult NewEpisodeReleased()
{
cDBContext tvContext = new cDBContext();
TVSerial_Episode_VM tves=new TVSerial_Episode_VM();
tves= tvContext.dbTvSerialEpisodes.Include("TVSerialEpisodeModel")
.Include("TVSerialModel").ToList();
return View(tves);
}

How to control the name of the foreign key relashionship object in EF Code First?

I have two entities in my EF Code first and they have a foreign key relationship.
public class Condition
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
public class ConditionGroup
{
public int Id { get; set; }
public Condition Condition { get; set; }
public int ConditionId { get; set; }
}
This is my entity map:
public class ConditionGroupMap : EntityTypeConfiguration<ConditionGroup>
{
public ConditionGroupMap()
{
this.ToTable("ConditionGroup");
this.HasKey(cg => cg.Id);
this.HasRequired(cg => cg.Condition).WithMany(c => c.ConditionGroups).HasForeignKey(cg => cg.ConditionId).WillCascadeOnDelete(true);
}
}
EF will create the a foreign key object in the database with the following Name:
ConditionGroup_Condition.
The problem is that this name collides with another object in the database for reasons which are beyond the scope of this question. So I would like to ask if there is a way to change this name?
Instead of doing it with the Fluent API, you could do it with Data Annotations:
public class ConditionGroup
{
public int Id { get; set; }
[ForeignKey("Condition")]
public int ConditionId { get; set; }
public Condition Condition { get; set; }
}
If that doesn't end up working you could always use the Column() Attribute to give it whatever column name you wished.

Entity Framework 4.3.1 how to create associations

my code like below
public class User
{
public int ID { get; set; }
public int BillingAddressID { get; set; }
public Address BillingAddress { get; set; }
public IList<Shipment> Shipments { get; set; }
}
public class Address
{
public int ID { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
public class Shipment
{
public int ID { get; set; }
public string State { get; set; }
public int DeliveryAddressID { get; set; }
public Address DeliveryAddress { get; set; }
public User ShipUser { get; set; }
//[ForeignKey("ShipUser")]
public int ShipUserID { get; set; }
//public int UserId { get; set; }
}
public class TestContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Address> Addresses { get; set; }
public DbSet<Shipment> Shipments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Shipment>().HasRequired(u => u.ShipUser)
.WithMany(d => d.Shipments)
.HasForeignKey(c => c.ShipUserID)
.WillCascadeOnDelete(false);
}
}
if i remove the override method,i will get an error "SqlException: Introducing FOREIGN KEY constraint 'FK_Shipments_Users_ShipUserID' on table 'Shipments' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors."
if i remove ShipUserID in Shipment Class,it will work ok,when i see the table that is created by ef,i found a column named Shipment_UserID in table Shipment.I don`t know why.
if rename the class indenty key to UserID,it also work ok.
I try it anyway,but I don`t know the reason, I need some books about EF associations.
If you don't have mapping specified without cascadeDelete=false for one relationship it will create multiple cascade paths if you have tow relationships to user from Shipment.
By convention you can use public
Public User ShipUser { get; set; }
public int ShipUserID { get; set; }
it will use ShipUserID as foreign key by convention.
If you remove ShipUserID Ef need to create his own foreign key to keep the relationship . that is your ' Shipment_UserID'
rename the class indenty key to UserID I don't understand what you meant.
Here is a good tutorial to start with

M:M Mapping - EF 4.3 CodeFirst (Existing Database)

I have two tables (Table A, Table B) joined with a join table (TableAB) with 3 payload columns. By Payload I mean columns apart from Id, TableAId, and TableBId.
I can insert into all tables successfully, but I need to insert data into one of the payload columns on Insert. I'm using EF 4.3, Fluent API. Can anyone help? Thanks in advance.
public class Organisation : EntityBase<int>, IAggregateRoot
{
public string Name { get; set; }
public string Url { get; set; }
public int CountryId { get; set; }
public int? OwnershipTypeId { get; set; }
public int OrganisationStatusId { get; set; }
public virtual ICollection<Feature> Features { get; set; }
public virtual ICollection<OrganisationType> OrganisationTypes { get; set; }
public virtual ICollection<PricePlan> PricePlans { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class User: EntityBase<Guid>, IAggregateRoot
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string JobTitle { get; set; }
public int? PhoneCallingCodeId { get; set; }
public int? PhoneAreaCode{ get; set; }
public string PhoneLocal { get; set; }
public int? MobileCallingCodeId { get; set; }
public int? MobileAreaCode { get; set; }
public string MobileLocal { get; set; }
public virtual ICollection<Organisation.Organisation> Organisations { get; set; }
}
public class OrganisationUser : EntityBase<int>, IAggregateRoot
{
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public int OrganisationRoleId {get; set;}//Foreign Key - have tried leaving it out, tried it as public virtual Organisation Organisation {get;set;
public bool IsApproved { get; set; }
}
public class SDContext : DbContext
{
public ObjectContext Core
{
get
{
return (this as IObjectContextAdapter).ObjectContext;
}
}
public IDbSet<User> User { get; set; }
public IDbSet<Organisation> Organisation { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Organisation>().HasMany(u => u.Users).WithMany(o => o.Organisations).Map(m =>
{
m.MapLeftKey("OrganisationId");
m.MapRightKey("UserId");
m.ToTable("OrganisationUser");
});
//I have tried specifically defining the foreign key in fluent, but I really need to understand how I can add the payload properties once I access and edit them.
Your mapping is not correct for your purpose. If you want to treat OrganisationUser as an intermediate entity between Organisation and User you must create relationships between Organisation and OrganisationUser and between User and OrganisationUser, not directly between Organisation and User.
Because of the intermediate entity which contains its own scalar properties you cannot create a many-to-many mapping. EF does not support many-to-many relationships with "payload". You need two one-to-many relationships:
public class Organisation : EntityBase<int>, IAggregateRoot
{
// ...
// this replaces the Users collection
public virtual ICollection<OrganisationUser> OrganisationUsers { get; set; }
}
public class User : EntityBase<Guid>, IAggregateRoot
{
// ...
// this replaces the Organisations collection
public virtual ICollection<OrganisationUser> OrganisationUsers { get; set; }
}
public class OrganisationUser : EntityBase<int>, IAggregateRoot
{
public int OrganisationId { get; set; }
public Organisation Organisation { get; set; }
public Guid UserId { get; set; }
public User User { get; set; }
// ... "payload" properties ...
}
In Fluent API you must replace the many-to-many mapping by the following:
modelBuilder.Entity<Organisation>()
.HasMany(o => o.OrganisationUsers)
.WithRequired(ou => ou.Organisation)
.HasForeignKey(ou => ou.OrganisationId);
modelBuilder.Entity<User>()
.HasMany(u => u.OrganisationUsers)
.WithRequired(ou => ou.User)
.HasForeignKey(ou => ou.UserId);
Your derived DbContext may also contain a separate set for the OrganisationUser entity:
public IDbSet<OrganisationUser> OrganisationUsers { get; set; }
It's obvious now how you write something into the intermediate table:
var newOrganisationUser = new OrganisastionUser
{
OrganisationId = 5,
UserId = 8,
SomePayLoadProperty = someValue,
// ...
};
context.OrganisastionUsers.Add(newOrganisastionUser);
context.SaveChanges();
If you want to make sure that each pair of OrganisationId and UserId can only exist once in the link table, it would be better to make a composite primary key of those two columns to ensure uniqueness in the database instead of using a separate Id. In Fluent API it would be:
modelBuilder.Entity<OrganisationUser>()
.HasKey(ou => new { ou.OrganisationId, ou.UserId });
More details about such a type of model and how to work with it is here:
Create code first, many to many, with additional fields in association table

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");
});