I'm trying to set a property in my entity based from another entity that has no relationship one to the other. The entity sets the properties from the database and I want one of the properties to be set from another table in database, but I can't get to the bottom of it.
For example,
public class First {
[Key]
public int ProdId { get; set; }
public string Supplier { get; set; }
public virtual ICollection<Log> Logs { get; set; }
[NotMapped]
public bool IsSavedForLater
{
get
{
return Logs.Where(l =>
{
var content = l.LogContent.JsonStringToObject<History>();
return (content.ProdId == ProdId && l.TableName == "Condition");
}).Any();
}
}
}
As you can see the property IsSavedForLater is [NotMapped] and I want this property to get set from the Logs,
Here is the log Entity,
public class Log
{
[Key]
public int LogId { get; set; }
public string LogContent { get; set; }
public string TableName { get; set; }
public DateTime LogDate { get; set; }
public string BlameName { get; set; }
public bool? Deleted { get; set; }
}
is it possible to navigate like this without any database relationship?
Guys I found my solution after a huge amount of time figuring it out.
What I did is, I added first another property in my First class like this
public class First {
[Key]
public int ProdId { get; set; }
public string Supplier { get; set; }
public string TableName { get; set; }
public virtual ICollection<Log> Logs { get; set; }
}
As you can see the First class has a new property TableName that is also in my Logs class like this,
public class Log
{
[Key]
public int LogId { get; set; }
public string LogContent { get; set; }
public string TableName { get; set; }
public DateTime LogDate { get; set; }
public string BlameName { get; set; }
public bool? Deleted { get; set; }
}
Then I added in the db context class a model builder like this,
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SmuForecasting>().HasKey(x => new { x.TableName }).HasMany(x => x.PsLogs).WithOptional().HasForeignKey(x => new { x.TableName });
}
That worked perfectly good for me but with side effects, it replaces the original key that was set to it in the beginning, so I ended up doing a total different approach.
Related
I am using EF Core together with ASP NET Core for my server, and when I am trying to update an existing value in the database I receive the following error:
Cannot insert explicit value for identity column in table 'TeambuildingType' when IDENTITY_INSERT is set to OFF.
What I am doing is this:
creating a Teambuilding element, with the foreign key for the TeamBuildingTypeId set to NULL initially
creating two TeambuildingType directly from the SQL Management Studio using INSERT INTO.... (the Id is auto incremented for both the Teambuilding and TeambuildingType)
trying to update the existing Teambuilding by adding either the TeambuildingTypeId like this: team.TeambuildingTypeId = 1 or team.Type = (object fetched from the database in the same context)
receiving the error from above in a catch
Here is my code:
TeamBuilding.cs
public class TeamBuilding
{
[Key]
public int Id { get; set; }
public string Title { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public double? TargetBudget { get; set; }
public TeambuildingStatus? Status { get; set; }
public int? TeambuildingTypeId { get; set; }
public virtual TeambuildingType Type { get; set; }
public int? LocationId { get; set; }
public virtual Location Location { get; set; }
public virtual ICollection<Participant> Participants { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public int TimePollId { get; set; }
public virtual TimePoll TimePoll { get; set; }
}
TeambuildingType.cs
public class TeambuildingType
{
[Key]
public int Id { get; set; }
public string Type { get; set; }
public virtual ICollection<TeamBuilding> Teambuildings { get; set; }
}
TeamBuildingForUpdateDto.cs
public class TeamBuildingForUpdateDto
{
[Required]
public int Id { get; set; }
public string Title { get; set; }
[DataType(DataType.DateTime)]
public DateTime StartDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime EndDate { get; set; }
public LocationViewModel Location { get; set; }
public TeambuildingStatus Status { get; set; }
public double TargetBudget { get; set; }
public TeamBuildingTypeDto Type { get; set; }
}
The update controller method:
[HttpPut]
public IActionResult UpdateTeamBuilding([FromBody]TeamBuildingForUpdateDto teamBuildingForUpdateDto)
{
try
{
var existingTeamBuilding = _service.GetByID(teamBuildingForUpdateDto.Id);
if (existingTeamBuilding == null)
{
return NotFound("There is no team buiding with such an ID");
}
_service.UpdateTeamBuilding(teamBuildingForUpdateDto);
return Ok();
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
The service method:
public TeamBuildingForUpdateDto UpdateTeamBuilding(TeamBuildingForUpdateDto teamBuildingDto)
{
var teamBuilding = _repositoryTeam.GetByID(teamBuildingDto.Id);
var type = _repositoryType.GetByID(teamBuildingDto.Type.Id);
Mapper.Map(teamBuildingDto.Type, type);
Mapper.Map(teamBuildingDto, teamBuilding);
teamBuilding.Type = type;
//OR
//teamBuilding.TeambuildingTypeId = type.Id;
//Neither from above works
_repositoryTeam.Edit(teamBuilding);
_repositoryTeam.Commit();
return teamBuildingDto;
}
Context using the Fluent API:
modelBuilder.Entity<Models.TeamBuilding>()
.HasOne(t => t.Type)
.WithMany(ty => ty.Teambuildings)
.HasForeignKey(t => t.TeambuildingTypeId);
modelBuilder.Entity<TeambuildingType>().ToTable("TeambuildingType");
modelBuilder.Entity<Models.TeamBuilding>().ToTable("TeamBuilding");
public DbSet<TeambuildingType> TeambuildingTypes { get; set; }
public DbSet<Models.TeamBuilding> TeamBuildings { get; set; }
I also don't receive this error on those models only, I receive the same thing on anything that uses FK and on where I try to insert a new value in there.
The relationship is one to many between the TeamBuilding and the TeambuildingType
What am I doing wrong?
I fixed the problem. As per mcbowes suggestion I checked the AutoMapper and what I send from the server, and I saw that I was trying to assign a TeamBuildingType in my TeamBuilding Type field, then trying to do the update.
I fixed the problem by not assigning any TeamBuildingType to the Type field (making it being null) and assigning only the TeamBuildingType primary key to the TeambuildingTypeId field. Now it does the update.
Thanks mcbowes for the suggestion.
I'd like to set one bool property in my controller and save it to the database. EF throws an error about other properties that are not even modified.
The association between entities 'User' and 'RequestDetail' with the
key value 'System.InvalidOperationException: The association between
entities 'User' and 'RequestDetail' with the key value '{Id: 40}' has
been severed but the relationship is either marked as 'Required' or is
implicitly required because the foreign key is not nullable. If the
dependent/child entity should be deleted when a required relationship
is severed, then setup the relationship to use cascade deletes.
If I call my method with an additional parameter it has to change one RequestDetail record's RequestSent property and that is working great.
But calling the method without this additional parameter it has to change this property on more than one RequestDetail records. And this is where it throws the error. I don't modify anything associated with User.
If it has to do more records at once it throws this error. Even if I rewrite the foreach into a while with FirstOrDefaults() and immediate SaveChanges() it throws error on the second round.
My method:
var head = await _ctx.RequestHeads.FirstOrDefaultAsync(x=>x.Id == d.Id);
if (!d.DetailId.HasValue) {
var details = _ctx.RequestDetails.Include(x=>x.BuyerUser)
.Where(x=>x.RequestHeadId == head.Id);
//not working, always throws an error if it has to modify more than one record
await details.ForEachAsync(detail => {
detail.RequestSent = true;
});
} else {
var detail = head.Details.FirstOrDefault(x=>x.Id == d.DetailId.Value); //works ok, always
detail.RequestSent = true;
}
await _ctx.SaveChangesAsync();
My models:
public class RequestHead
{
[Key, MaxLength(15)]
public string Id { get; set; }
public DateTime CreateDate { get; set; }
public int CreateUserId { get; set; }
[ForeignKey("CreateUserId")]
public User CreateUser { get; set; }
public DateTime? AcceptDate { get; set; }
public int? AcceptUserId { get; set; }
[ForeignKey("AcceptUserId")]
public User AcceptUser { get; set; }
public DateTime? CloseDate { get; set; }
public int? CloseUserId { get; set; }
[ForeignKey("CloseUserId")]
public User CloseUser { get; set; }
public int? CloseReason { get; set; }
public bool IsArchive { get; set; }
[MaxLength(8)]
public string OrganizationCode { get; set; }
[ForeignKey("OrganizationCode")]
public Organization Organization { get; set; }
public virtual ICollection<RequestDetail> Details { get; set; }
public virtual ICollection<RequestAttachment> Attachments { get; set; }
}
public class RequestDetail
{
[Key]
public int Id { get; set; }
public string RequestHeadId { get; set; }
[ForeignKey("RequestHeadId")]
public RequestHead RequestHead { get; set; }
[MaxLength(20)]
public string ProductCode { get; set; }
[ForeignKey("ProductCode")]
public Product Product { get; set; }
public string ProductName { get; set; }
public bool NoProductCode { get; set; }
public string Description { get; set; }
public DateTime CreateDate { get; set; }
public int CreateUserId { get; set; }
[ForeignKey("CreateUserId")]
public User CreateUser { get; set; }
public DateTime? DelegateDate { get; set; }
public int? DelegateUserId { get; set; }
[ForeignKey("DelegateUserId")]
public User DelegateUser { get; set; }
public int? BuyerUserId { get; set; }
[ForeignKey("BuyerUserId")]
public User BuyerUser { get; set; }
public bool RequestSent { get; set; }
public virtual ICollection<RequestAttachment> Attachments { get; set; }
}
Context:
modelBuilder.Entity<RequestHead>()
.HasOne(r=>r.CreateUser)
.WithOne().OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<RequestHead>()
.HasMany(r => r.Details)
.WithOne(x=>x.RequestHead)
.HasForeignKey(rd => rd.RequestHeadId);
modelBuilder.Entity<RequestDetail>()
.HasOne(r=>r.CreateUser)
.WithOne().OnDelete(DeleteBehavior.Restrict);
The solution was to change RequestDetail<=>User relations from WithOne() to WithMany(). Although the error message is somewhat misleading, a possible explanation from #IvanStoev is the following:
I guess with one-to-one the code expects single record, so when the
second record with the same FK comes in, they get confused and decided
that the record is deleted
Song has a many to many relationship with it's self. I store these ids in a class called SimilarVersion with both id columns.
public class Song
{
public int Id { get; set; }
public string AudioName { get; set; }
public string ArtistName { get; set; }
...
public virtual ICollection<SimilarVersion> SimilarVersions { get; set; } = new List<SimilarVersion>();
}
public class SimilarVersion
{
public int Id { get; set; }
public int? Song_Id1 { get; set; }
}
View Models:
public class SongDto
{
public int Id { get; set; }
public string AudioName { get; set; }
public string ArtistName { get; set; }
...
public ICollection<SimilarSongDto> SimilarSongDtos { get; set; } = new List<SimilarSongDto>();
}
public class SimilarSongDto
{
public int Id { get; set; }
public string AudioName { get; set; }
public string ArtistName { get; set; }
...
}
The SimilarVersion table in my database now has Id,Song_Id,Song_Id1, as EF has generated Song_Id. How do I get to use that EF generated column in my code though?
_similarVersionService.GetSimiliarVersion().Song_Id will give me an error because there is no property in the class called that. I could manually add it to the class like I have done with Song_Id1 and remove the collection from the other class but I think I must be doing something wrong. Also please tell me if there is a better way of mapping this.
I tried adding public int Song_Id { get; set; } and it just made another column in my table called Song_Id2.
public ActionResult Song(int id)
{
//Map the domainModel to songViewModel
var songDto = Mapper.Map<Song, SongDto>(_songService.GetSong(id));
//Get all of the songs where the id == the Song_Id column in similar version table
var songs = _songService.GetSongs().ToList()
.Where(x => x.SimilarVersions.Any(z => z.Song_Id == songDto.Id))
.ToList(); //z.Song_Id no definition found
//Map the Song domain to SimilarSong ViewModel and assign it to the songDto to be passed to the view
songDto.SimilarSongDtos = Mapper.Map<ICollection<Song>, ICollection<SimilarSongDto>>(songs);
return View(songDto);
}
Edit. Trying to add to a row based on Admir answer:
var songToUpload = new Song
{
AudioName = uploadSongDtos[i].AudioName.Trim(),
ArtistName = uploadSongDtos[i].ArtistName,
};
foreach (var compareAgainstString in _songService.GetSongs().ToDictionary(x => x.Id, x => x.AudioName))
{
var score = SearchContext.Levenshtein.iLD(songToUpload.AudioName, compareAgainstString.Value);
//Don't add the current song
if (score < 50 && songToUpload.Id != compareAgainstString.Key)
songToUpload.SimilarVersionsWhereSimilar.Add(new SimilarVersion { SimilarId = compareAgainstString.Key });
}
Both OriginalId and SimilarId are assigned to whatever the id of songToUpload.Id is given the relationship we defined in models, which is correct for OriginalId but it is also overriding my custom set SimilarId above. How can I stop this?
You can take this approach:
public class Song
{
public int Id { get; set; }
public string ArtistName { get; set; }
public virtual IList<Similarity> SimilaritiesWhereOriginal { get; set; }
public virtual IList<Similarity> SimilaritiesWhereSimilar { get; set; }
}
public class Similarity
{
public int Id { get; set; }
public int OriginalId { get; set; }
public virtual Song Original { get; set; }
public int SimilarId { get; set; }
public virtual Song Similar { get; set; }
}
public class ApplicationDbContext : DbContext
{
public DbSet<Song> Songs { get; set; }
public DbSet<Similarity> Similarities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Song>().HasMany(x => x.SimilaritiesWhereOriginal).WithRequired(x => x.Original).WillCascadeOnDelete(false);
modelBuilder.Entity<Song>().HasMany(x => x.SimilaritiesWhereSimilar).WithRequired(x => x.Similar).WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
}
Similarity class shows relationship between "original" song and "similar" song. This class replaces EF auto-generated table with your own many-2-many relationship table that you can access from the code.
It is likely the ID is actually generated by your Store. Call Context.SaveChanges() to create it, then read the ID.
I am a VB.NET programmer, but I am trying to learn C# and MVC in my spare time. I am using ASP.NET MVC 5.1.0.0 and I am trying to do code-First database creation in a local instance of SQL Server.
I was able to get the first database table to update in the database when I ran Update-Database from within the IDE, but when I added a second table that has a PK/FK relationship with the first, I am getting a red line under [ForeignKey] which reads
Does not contain a constructor that takes 1 arguments
I have been searching all over and not getting anywhere. Any suggestions or help would be appreciated. By the way, the first table is a PK/FK relationship to the AspNetUsers table.
public class BuildDatabase : IdentityUser
{
public virtual Companies Companies { get; set; }
public virtual NotaryProfile NotaryProfile { get; set; }
}
public class Companies
{
[Key]
[Column("CompanyID")] // Did this as the database will reflect TableName_ColumnName instead.
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public bool IsActive { get; set; }
public bool IsNotary { get; set; }
public virtual ICollection<NotaryProfile> NotaryProfile { get; set; }
}
public class NotaryProfile
{
[Key]
public int NotaryID { get; set; }
public string NamePrefix { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public string NameSuffix { get; set; }
public bool IsActive { get; set; }
public int DefaultState { get; set; }
public int DefaultCounty { get; set; }
public bool IsSigningAgent { get; set; }
public bool HasABond { get; set; }
public decimal BondAmount { get; set; }
public bool HasEandO { get; set; }
public decimal EandOAmount { get; set; }
public bool ElectronicNotarizationsAllowed { get; set; }
public string ElectronicTechnologyUsed { get; set; }
public string ComissionNumber { get; set; }
public DateTime CommissionIssued { get; set; }
public DateTime CommssionOriginal { get; set; }
public DateTime CommissionExpires { get; set; }
public DateTime CommissionFiledOn { get; set; }
public string SOSAuditNumber { get; set; }
public string CommissionDesc { get; set; }
[Foreignkey("CompanyID")] // Companies.CompanyID = PK
public int CompanyID { get; set; } // PK/FK relationship.
public Companies Companies { get; set; } // Reference to Companies table above.
}
public class SchemaDBContext : IdentityDbContext<BuildDatabase>
{
public SchemaDBContext()
: base("DefaultConnection"){}
public DbSet<Companies> Companies { get; set; }
public DbSet<NotaryProfile> NotaryProfile { get; set; }
}
One of your classes (probably NotaryProfile) needs to reference another object (the foreign key relationship) but there is no constructor in that class that accepts an argument to establish that relationship, e.g.:
public NotaryProfile(int companyId) {
this.companyId = companyId;
}
BTW, a better way to establish that relationship is to use the actual class type rather than the ID, as in:
public class NotaryProfile {
...
public Company Company { get; set; }
// Instead of this:
// public int CompanyID { get; set; } // PK/FK relationship.
...
}
See also:
C# “does not contain a constructor that takes '1' arguments”
Does not contain a constructor that takes 2 arguments
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.