Foreign key value not populating automatically - c#

I've created a foreign key reference to the 'ApplicationUser' entity in my 'YogaSpace' entity seen below, but when I create a new YogaSpace and save it to the DB the column 'ApplicationUserRefId' is null? Shouldn't it contain the user id from application user without me inserting it into the entity before I save it? I know the answer would seem to be yes because I have another member in 'YogaSpace' called Images and it gets the 'YogaSpace' entity id automatically without me inserting it into the 'Images' entity before I save. So I don't have to insert the id there. How come it doesn't insert the user id with 'YogaSpace'?
public class YogaSpace
{
public int YogaSpaceId { get; set; }
public virtual ICollection<YogaSpaceImage> Images { get; set; }
[MaxLength(128)]
public string ApplicationUserRefId { get; set; }
[ForeignKey("ApplicationUserRefId")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
public class ApplicationUser : IdentityUser
{
public DateTime MembershipCreated { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? Birthdate { get; set; }
public Gender Gender { get; set; }
public virtual ICollection<YogaSpace> YogaSpaces { get; set; }
}
public class YogaSpaceImage
{
public int YogaSpaceImageId { get; set; }
public byte[] Image { get; set; }
public byte[] ImageThumbnail { get; set; }
public string ContentType { get; set; }
public int Ordering { get; set; }
[Index]
public int YogaSpaceRefId { get; set; }
[ForeignKey("YogaSpaceRefId")]
public virtual YogaSpace YogaSpace { get; set; }
}
Here is how I create a 'YogaSpace' entity. You can see I don't put anything into 'ApplicationUserRefId', BUT I expect it to autopopulate with user id from Application User, just like YogaSpacerefId gets auto populated when I create an image and save it.
var newSpace = new YogaSpace
{
Overview = new YogaSpaceOverview
{
Title = viewModel.Title,
Completed = ListingComplete.Incomplete
},
Listing = new YogaSpaceListing
{
Accommodation = (YogaSpaceAccommodation)viewModel.YogaSpaceAccommodation,
SpaceLocation = (YogaSpaceLocation)viewModel.YogaSpaceLocation,
SpaceType = (YogaSpaceType)viewModel.YogaSpaceType
},
Details = new YogaSpaceDetails
{
Completed = ListingComplete.Complete
},
Address = new YogaSpaceAddress
{
Completed = ListingComplete.Incomplete
},
DateCreated = DateTime.Now
};
yogaSpaceRepository.InsertOrUpdate(newSpace);
yogaSpaceRepository.Save();

Related

.NET Foreign Key Cannot be Inserted

I have used foreign keys many times before and set up these models just the same however I'm getting this error, the error also occurs when writing usertableID:
A foreign key value cannot be inserted because a corresponding primary key value does not exist. [ Foreign key constraint name = FK_dbo.Outreaches_dbo.OutreachNames_OutreachNamesID ]
Can anyone explain?
Code causing error:
foreach (var item in records)
{
List<string> foundEmails = EmailScraper.Main(item.domain);
string[] emails = foundEmails.ToArray();
var outreach = new Outreach {
domain = item.domain,
email1 = foundEmails.ElementAtOrDefault(0),
email2 = foundEmails.ElementAtOrDefault(1),
email3 = foundEmails.ElementAtOrDefault(2),
email4 = foundEmails.ElementAtOrDefault(3),
email5 = foundEmails.ElementAtOrDefault(4),
email6 = foundEmails.ElementAtOrDefault(5),
UserTableID = UserTableID,
OutreachNamesID = listNumber
};
db.OutreachLists.Add(outreach);
db.SaveChanges();
}
var outreachlist = new OutreachNames
{
ID = listNumber,
listName = model.listName,
listCount = count,
listSent = 0,
unread = 0,
replyRate = 0,
UserTableID = UserTableID,
};
db.OutreachNames.Add(outreachlist);
db.SaveChanges();
Model Outreach:
namespace Linkofy.Models
{
public class Outreach
{
public int ID { get; set; }
public int? OutreachNamesID { get; set; }
public virtual OutreachNames OutreachNames { get; set; }
public string name { get; set; }
[Required]
public string domain { get; set; }
public string email1 { get; set; }
public string email2 { get; set; }
public string email3 { get; set; }
public string email4 { get; set; }
public string email5 { get; set; }
public string email6 { get; set; }
public string email7 { get; set; }
public string email8 { get; set; }
public int? UserTableID { get; set; }
public virtual UserTable UserTable { get; set; }
}
}
Model OutreachNames:
namespace Linkofy.Models
{
public class OutreachNames
{
public int ID { get; set; }
[Required]
public string listName { get; set; }
public int listCount { get; set; }
public int listSent { get; set; }
public int unread { get; set; }
public int replyRate { get; set; }
public virtual ICollection<Outreach> OutreachLists { get; set; }
public int? UserTableID { get; set; }
public virtual UserTable UserTable { get; set; }
}
}
When saving your Outreach you are setting the FK OutreachNamesID to an ID of a record which doesn't exist yet. You need to create this record first or use Entity Framework to create OutreachNames as a child entity. Both entities need to be persisted to the db in one transaction.
You can create the child entity inside of the parent and persist them in one go like this:
var outreach = new Outreach
{
OutreachNames = new OutreachNames
{
...
}
}
db.OutreachLists.Add(outreach);
db.SaveChanges();

EF Core 2 Not Saving Related Entities

I have an implicit one to many relationship set up between Template and TemplateParameters. As far as I can tell, I am following conventions. However, when I save a Template, the children are not discovered and saved with it.
public class Template
{
#region Properties
public int TemplateId { get; set; }
public string UserId { get; set; }
public DateTime Created { get; set; }
public DateTime Published { get; set; }
public bool Deleted { get; set; }
public int Likes { get; set; }
public int Shares { get; set; }
public int Downloads { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
#endregion
#region Navigation
//navigation properties
public ApplicationUser User { get; set; }
public IEnumerable<Wave> Waves { get; set; }
public IEnumerable<TemplateParameter> TemplateParameters;
public IEnumerable<ApplicationUser> Subscribers;
#endregion
}
public class TemplateParameter
{
public int TemplateParameterId { get; set; }
public int TemplateId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double? Value { get; set; }
public DateTime Created { get; set; }
//navigation properties
public virtual Template Template { get; set; }
}
[HttpPost]
[Route("SaveTemplate")]
public TemplateViewModel SaveTemplate([FromBody] TemplateViewModel vm)
{
//get the current userId
var user = _userManager.GetUserAsync(HttpContext.User).Result;
var token = User;
//map params
var parameters = vm.Parameters.Select(r => new TemplateParameter()
{
Name = r.Name,
Description = r.Description,
Created = DateTime.Now,
}).ToList();
//map the vm to the model
var template = new Template()
{
Name = vm.Name,
Description = vm.Description,
Created = DateTime.Now,
UserId = user.Id,
TemplateParameters = parameters,
};
//save the template
template = _templateService.SaveTemplate(template);
//map id back to the view model
vm.TemplateID = template.TemplateId;
return vm;
}
public Template SaveTemplate(Template template)
{
_context.Templates.Add(template);
_context.SaveChanges();
return template;
}
Can anyone spot what I'm doing wrong here? The template saves fine, but the child collections does not. I'm using the same pattern elsewhere in my project and it seems to work without issue. Thank you in advance for your help.

How to fully construct the newly added Entity

In my project i need to add Sales leads to the data context. The sales person user adds the leads and I need to send the email to manager for the Lead.
public partial class Lead
{
public Lead()
{
this.LeadActivities = new HashSet<LeadActivity>();
}
public long LeadID { get; set; }
public System.DateTime CreatedAt { get; set; }
public long CompanyID { get; set; }
public long ProductID { get; set; }
public long CreatedByUserID { get; set; }
public string Remarks { get; set; }
public LeadStatusEnum StatusID { get; set; }
public virtual Company Company { get; set; }
public virtual Product Product { get; set; }
public virtual User User { get; set; }
public virtual ICollection<LeadActivity> LeadActivities { get; set; }
}
[Serializable]
public partial class Person
{
public Person()
{
this.Contacts = new HashSet<Contact>();
this.Users = new HashSet<User>();
}
public long PersonID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Designation { get; set; }
public Nullable<int> Gender { get; set; }
public Nullable<int> Title { get; set; }
public int StatusID { get; set; }
public string Thumbnail { get; set; }
public string Email { get; set; }
public virtual ICollection<Contact> Contacts { get; set; }
public virtual ICollection<User> Users { get; set; }
}
In the above entity, I have property UserID that is associated to Person table through CreatedByUserID. When I add the new lead, by following code, the User field remains null. Do I need to reconstruct it? if yes then how.
Edit1
Entity Creation is done by following code
Entity = new Model.Lead
{
CreatedAt = DateTime.Now,
CreatedByUserID = SessionManagement.GeneralSession.UserDetail.UserID
};
Entity.CreatedAt = Convert.ToDateTime(txtTimestamp.Value);
Entity.CompanyID = Convert.ToInt64(ddlCompany.SelectedValue);
Entity.CreatedByUserID = Convert.ToInt64(ddlUser.SelectedValue);
Entity.ProductID = Convert.ToInt64(lstProducts.SelectedValue);
Entity.Remarks = txtRemarks.Text;
DataSource.Leads.Add(Entity);
DataSource.SaveChanges();
Virtual lazy loading only works with proxy instances. Since you're explicitly constructing your Lead entity, lazy loading of the User navigation property after inserting the entity will not work.
Instead, you should use the DbSet.Create method to new up an instance of the derived proxy type. Then perform your insert, which will attach to the context, and lazy loading will subsequently work.
Alternatively, you can use your existing POCO, perform the insert and then fetch your inserted entity as its proxy from the DbSet by using the DbSet.Find method.
You should also check and make sure your foreign key id and navigation properties are correctly mapped, since properties CreatedByUserID and User would not be automatically associated by convention.

ASP.NET MVC /Entity Framework Error - Invalid column name 'Environment_Id'

I'm new to ASP.NET MVC and EF hopefully this is not a silly question
When i pass model to view i'm getting this error - Exception Details: System.Data.SqlClient.SqlException: Invalid column name 'Environment_Id'.
Model nor database table has a property by that name. Could any guide me on this?.
**Here is the Version Model Class**
public partial class Version
{
public Version()
{
this.ProfileVersions = new List<ProfileVersion>();
this.ServerInfoes = new List<ServerInfo>();
}
public int Id { get; set; }
public string Number { get; set; }
public string Tag { get; set; }
public string Owner { get; set; }
public string Approver { get; set; }
public string Description { get; set; }
public virtual ICollection<ProfileVersion> ProfileVersions { get; set; }
public virtual ICollection<ServerInfo> ServerInfoes { get; set; }
}
**Profile Version Class**
public partial class ProfileVersion
{
public ProfileVersion()
{
this.PlatformConfigurations = new List<PlatformConfiguration>();
}
public int Id { get; set; }
public int ProfileId { get; set; }
public int EnvironmentId { get; set; }
public int VersionId { get; set; }
public Nullable<bool> Locked { get; set; }
public string LockedBy { get; set; }
public string Comments { get; set; }
public Nullable<int> Active { get; set; }
public virtual Environment Environment { get; set; }
public virtual ICollection<PlatformConfiguration> PlatformConfigurations { get;
set; }
public virtual PlatformProfile PlatformProfile { get; set; }
public virtual Version Version { get; set; }
}
**ServerInfo**
public partial class ServerInfo
{
public ServerInfo()
{
this.PlatformConfigurations = new List<PlatformConfiguration>();
}
public int Id { get; set; }
public string ServerName { get; set; }
public int ProfileId { get; set; }
public int VersionId { get; set; }
public int EnvironmentId { get; set; }
public string ServerType { get; set; }
public Nullable<short> Active { get; set; }
public string Domain { get; set; }
public string Location { get; set; }
public string IP { get; set; }
public string Subnet { get; set; }
public string Gateway { get; set; }
public Nullable<int> VLan { get; set; }
public string DNS { get; set; }
public string OS { get; set; }
public string OSVersion { get; set; }
public string Func { get; set; }
public Nullable<short> IISInstalled { get; set; }
public string ADDomainController { get; set; }
public string ADOrganizationalUnit { get; set; }
public string ADGroups { get; set; }
public string LastError { get; set; }
public Nullable<System.DateTime> LastUpdate { get; set; }
public virtual Environment Environment { get; set; }
public virtual ICollection<PlatformConfiguration> PlatformConfigurations { get;
set; }
public virtual PlatformProfile PlatformProfile { get; set; }
public virtual Version Version { get; set; }
public virtual VMConfiguration VMConfiguration { get; set; }
}
**Controller Code-**
public ViewResult Index(string id )
{
var profileVerList = from ver in _context.Versions
where !(from pfv in _context.ProfileVersions
select pfv.VersionId).Contains(ver.Id)
select ver;
var bigView = new BigViewModel
{
VersionModel = profileVerList.ToList(),
};
return View(model: bigView);
}
**In the View where the exception is thrown**
#Html.DropDownList(
"SelectedVersionID",
new SelectList(
Model.VersionModel.Select(x => new { Value = x.Id, Text = x.Number}),
"Value",
"Text"
)
)
In your ProfileVersion and ServerInfo entities you have an Environment navigation property. By default, Entity Framework will try to create a database column called [Property Name]_[Referenced class PK]. In your scenario, that's Environment_Id. The problem, right now, is that you have not done a migration to have this database column created.
If I had to imagine what happened here, I'd say you first created the classes with EnvironmentId properties, migrated, then later decided to add the navigation properties, Environment to each, expecting EF to associate that with your existing EnvironmentId properties. That's where you went wrong. As I said above, EF convention is to look for a database column named Environment_Id, so if you want EF to use EnvironmentId instead, you just need to tell it so with the ForeignKey data annotation:
[ForeignKey("Environment")]
public int EnvironmentId { get; set; }
In My Case I have added My Primary Key Relationship to Same Key .. SO I have simply remove..
I realize this question is 3 years old now, but I saw a different reason for the error - both in the original question and in my own code that was pretty similar. And, in my case, I had the same error as stated above.
I had a "MY_ACTIONS" table with an ID and Name pair that I wanted to be added to a dropdown. Here's the model:
namespace TestSite.Models
{
public class MY_ACTIONS
{
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MY_ACTIONS()
{
this.o_actions = new HashSet<MY_ACTIONS>();
}
[Key]
public int action_id { get; set; }
[StringLength(100)]
public string action_name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MY_ACTIONS> o_actions { get; set; }
}
}
And to get an action to display on the dropdown it had an ID set in an int field called LASTACTION in my main table. In that model I had declared the ForeignKey relationship:
namespace TestSite.Models
{
[Table("MAIN_TABLE")]
public partial class MAIN_TABLE
{
[Key]
public int MAIN_TABLE_ID { get; set; }
public int LASTACTION { get; set; } // this would carry a number matching action_id
[ForeignKey("LASTACTION")]
public virtual MY_ACTIONS MY_ACTIONS { get; set; }
}
}
I had the error Invalid column name 'MY_ACTIONS_action_id' when loading this dropdown in my view:
#Html.DropDownList("lastaction", null, htmlAttributes: new { #class = "form-control" })
...for which I was using this ViewBag in my Controller function:
Model1 db = new Model1(); // database context
MAIN_TABLE o_main = new MAIN_TABLE();
o_main.lastaction = 2;
ViewBag.lastaction = new SelectList(db.MY_ACTIONS, "action_id", "action_name", o_main.lastaction);
If I did not have my FK relationship declared:
[ForeignKey("LASTACTION")]
public virtual MY_ACTIONS MY_ACTIONS { get; set; }
I probably also would've had the same issue. Having the representation of a virtual instance requires linking it with some physical property. This is similar to how this:
public virtual Environment Environment { get; set; }
Should be:
[ForeignKey("EnvironmentId")]
public virtual Environment Environment { get; set; }
in the ProfileVersion class, in the question, above, assuming that EnvironmentId is the Primary Key in a table called Environment (that model is not shown above).
For me, though, I already had that and I was still getting the error, so doing that still might not solve everything.
Turns out all I had to do was get rid of that ICollection<MY_ACTIONS> o_actions in the MY_ACTIONS model and the this.o_actions = new HashSet<MY_ACTIONS>(); line and it all went through fine.
There are many such lists and ICollections in play in the question above, so I would wager something is wrong with having them, as well. Start with just a plain model that represents the fields, then add in your virtual objects that represent tables linked to with foreign keys. Then you make sure your dropdown loads. Only after that should you start adding in your ICollections, HashSets, Lists<T> and other such amenities that are not actually physically part of the database - this can throw off Entity Framework into thinking it needs to do something with them that it doesn't need to do.

One To Many relationship entity framework without Code First Model Creation

EDIT: (simplified solution)
I'm t rying to insert a Picture Entity in an Ad Entity that can have N Pictures.
The Pictures are related with Ads.
Ad Model:
public class Ad
{
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Picture> Pictures { get; set; }
}
Picture Model:
public class Picture
{
public int Id { get; set; }
public string URL { get; set; }
public int Ad_Id { get; set; }
public virtual Ad Ad { get; set; }
public int PictureType_Id { get; set; }
public virtual PictureType PictureType { get; set; }
}
PictureType Model:
public class PictureType
{
public int Id { get; set; }
public string Name { get; set; }
}
Ad Service:
Picture picture = new Picture()
{
Ad_Id = adId,
Filename = newFileName,
PictureType_Id = pictureType.Id
};
_pictureService.CreatePicture(picture);
Picture Service:
public void CreatePicture(Picture picture)
{
_pictureRepository.Add(picture);
_pictureRepository.Save();
}
ERROR:
The query generated by this code is:
Execute Reader "insert [dbo].[Pictures]([Name], [Filename], [URL], [PictureType_Id], [Ad_Id], [PictureType_Id1], [Ad_Id1])
values (null, #0, null, #1, #2, null, null)"
And I Get the ERROR:
Thrown: "Invalid column name 'PictureType_Id1'.
Invalid column name 'Ad_Id1'." (System.Data.SqlClient.SqlException) Exception Message = "Invalid column name 'PictureType_Id1'.\r\nInvalid column name 'Ad_Id1'.
Exception Type = "System.Data.SqlClient.SqlException", Exception WinRT Data = ""
You are missing a PK/FK relationship between Ad and Picture. The default would be Ad_Id
public class Picture
{
public int Id { get; set; }
public string URL { get; set; }
public int Ad_Id { get; set; }
public virtual Ad Ad { get; set; }
}
The same is needed in your database.
And a relationship needs to be defined between the entities (something like this)
this.HasMany(c => c.AdPictures)
.WithRequired(p => p.Ad)
.HasForeignKey(k => k.Ad_Id);
Based on the additional information the problem appears to be:
Ad has a relationship with an intermediate table AdPicture but Picture has a direct relationship to Ad where as it should also have a relationship with the intermediate tableAdPicture?
this:
public class Picture
{
public int Id { get; set; }
public string URL { get; set; }
public virtual AdPicture AdPicture { get; set; }
}
or this:
public class Picture
{
public int Id { get; set; }
public string URL { get; set; }
public virtual ICollection<AdPicture> AdPictures { get; set; }
}
Is this make sense? :
Changes in Picture Model:
public class Picture
{
// Primary properties
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Filename { get; set; }
public string URL { get; set; }
// Navigation properties
//public int PictureType_Id { get; set; }
public virtual PictureType PictureType { get; set; }
//public int Ad_Id { get; set; }
public virtual Ad Ad { get; set; }
}
Change in Ad Service:
// Insert Picture
Picture picture = new Picture()
{
Ad = _adRepository.GetById(adId),
Filename = newFileName,
PictureType = _pictureTypeService.GetPictureTypeById(pictureType.Id)
};
_pictureService.CreatePicture(picture);
Everything else remain the same.
Now it's working but it does not seem to be the best solution because I have 2 roundtrips to the database to get the Ad entity and the PictureType entity.
Am I right?

Categories