I have below classes spacetype and mastersection which is having below structure
public class SpaceType
{
public Guid Id { get; set; }
[ForeignKey("MasterSection")]
public string MasterSectionName { get; set; }
public virtual MasterSection MasterSection { get; set; }
[ForeignKey("LibrarySpaceTypeCategory")]
public Guid? LibrarySpaceTypeCategoryId { get; set; }
public virtual LibrarySpaceTypeCategory LibrarySpaceTypeCategory { get; set; }
[Column(TypeName = "jsonb")]
public MechanicalData MechanicalData { get; set; }
}
public class MasterSection
{
[Key, GraphQLNonNullType]
public string Name { get; set; }
public List<SectionEmployee> SectionOwners { get; set; } = new List<SectionEmployee>();
[ForeignKey("ParentMasterSection"), GraphQLIgnore]
public string ParentMasterSectionName { get; set; }
public virtual MasterSection ParentMasterSection { get; set; }
}
and i am trying to update mastersection object for all spacetypes like as below
var spaceTypes = ctx.SpaceTypes.ToList();
foreach(var spacetype in spaceTypes)
{
spacetype.MasterSection = masterSectionMappedLibrary["Space Type"];
}
ctx.SaveChanges();
and below is the data that I am getting from masterSectionMappedLibrary["Space Type"]
and getting an error here ctx.SaveChanges(); like Duplicate key violates unique constraint on PK_Mastersections.
Could any one please let me know where i am doing wrong and i am using EF core with postgreSQL.
Many thanks in advance
Update:
Try this
var spaceTypes = ctx.SpaceTypes.ToList();
foreach(var spacetype in spaceTypes)
{
spacetype.MasterSectionName = masterSectionMappedLibrary["Space Type"].Name;
}
ctx.UpdateRange(spaceTypes);
ctx.SaveChanges();
After you save the updated value to db, try to retrieve it again
var spaceTypesUpdated = ctx.SpaceTypes
.Include("MasterSection.ParentMasterSection")
.Include("SectionOwners")
.ToList();
// serialize spaceTypesUpdated to json
Related
I'm trying to Deserialize data into an object, and then add that object to a sqlite database with Entity Framework.
The first part is working fine.
But if try to add the object to the database I get this error:
System.InvalidOperationException: 'The instance of entity type 'Client' cannot be
tracked because another instance with the same key value for {'id'} is already being
tracked. When attaching existing entities, ensure that only one entity instance with a
given key value is attached. Consider using
'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key
values.'
Is it not possible to add the Rootobject with all the subclasses in one go?
Here is my code, I did not include all the sub classes.
All classes has an Id field:
HttpClient client = new HttpClient();
//Add headers etc. ...
var result = await client.GetAsync(url);
string? content = await result.Content.ReadAsStringAsync();
var TimeEntries = JsonConvert.DeserializeObject<Rootobject>(content);
using (var database = new DataContext())
{
database.Add(TimeEntries);
database.SaveChanges();
}
public class DataContext : DbContext
{
public DbSet<Rootobject>? RootObjects { get; set; }
public DbSet<Link>? Links { get; set; }
public DbSet<Time_Entry>? Time_Entries { get; set; }
public DbSet<User>? Users { get; set; }
public DbSet<Client>? Clients { get; set; }
public DbSet<Project>? Projects { get; set; }
public DbSet<Task>? Tasks { get; set; }
public DbSet<User_Assignment>? User_Assignments { get; set; }
public DbSet<Task_Assignment>? Task_Assignments { get; set; }
public DbSet<External_Reference>? External_References { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder dbContextOptionsBuilder)
{
dbContextOptionsBuilder.UseSqlite("Data Source=data.db");
}
}
public class Rootobject
{
public int Id { get; set; }
public ICollection<Time_Entry>? Time_entries { get; set; }
public int Per_page { get; set; }
public int Total_pages { get; set; }
public int Total_entries { get; set; }
public int ?Next_page { get; set; }
public int ?Previous_page { get; set; }
public int Page { get; set; }
public Link? Links { get; set; }
}
Basically when calling Put method from controller and trying to update properties im getting conflict from Db.
Using repository pattern with unit of work.
Car model -
public class Car : BaseModel
{
public Guid CategoryId { get; set; }
public Category Category { get; set; }
public Guid ManufacturerId { get; set; }
public Manufacturer Manufacturer { get; set; }
public Guid ManufacturerModelId { get; set; }
public ManufacturerModel ManufacturerModel { get; set; }
public DateTime ManufactureDate { get; set; }
public string Engine { get; set; }
public Guid FuelTypeId { get; set; }
public FuelType FuelType { get; set; }
public Guid FrameTypeId { get; set; }
public FrameType FrameType { get; set; }
public Guid ColorId { get; set; }
public Color Color { get; set; }
public Guid TransmissionId { get; set; }
public Transmission Transmission { get; set; }
public Guid DefectsId { get; set; }
public Defects Defects { get; set; }
public Guid SteeringWheelPosId { get; set; }
public SteeringWheelPos SteeringWheelPos { get; set; }
public Doors Doors { get; set; }
public int Seats { get; set; }
public DateTime VehicleInspection { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
}
BaseModel class
public class BaseModel : IBaseModel
{
public BaseModel()
{
Id = Guid.NewGuid();
CreatedOn = DateTime.Now;
}
[Key]
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; }
}
put method (im using cqrs here, and controller already passes carDto to method)
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
if(request.obj == null)
{
throw new StatusCodeException(HttpStatusCode.BadRequest, "Object is empty");
}
var DbEntry = uow.carRepository.GetById(request.Id);
if (DbEntry == null)
{
throw new StatusCodeException(HttpStatusCode.NotFound, "was not found in database", request.Id);
}
request.obj.Id = request.Id;
var s = uow.Mapper.Map(request.obj, DbEntry);
uow.carRepository.Update(s);
uow.Commit();
return Unit.Value;
}
//Update method in generic repository class
public void Update(T obj)
{
context.Attach(obj);
context.Entry(obj).State = EntityState.Modified;
}
I can't find where i do something wrong. Checked with breakpoints, data is correct everywhere. getting error when calling uow to commit changes. Thank you. Looking forward.
The reason why this error happens is because, your foreign key 'DefectId' in 'Car' probably has value 0.
When entity framework core encounters value 0 for foreign key, it throws this kind of error, because it cannot insert foreign value 0 which is the primary key of some object. Obviously, primary keys cannot be value 0.
Hope, this answers to your question.
Hi everyone I am trying to update my local sqldb without success.
I created a DbContext:
public class DbContextWeather1 : DbContext
{
public DbSet<WeatherRoot> Weathers { get; set; }
}
Where WeatherRoot is:
public class Coord
{
[JsonProperty("lon")]
public double Longitude { get; set; }
[JsonProperty("lat")]
public double Latitude { get; set; }
}
public class Sys
{
[JsonProperty("country")]
public string Country { get; set; }
}
public class Weather
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("main")]
public string Main { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("icon")]
public string Icon { get; set; }
}
public class Main
{
[JsonProperty("temp")]
public double Temperature { get; set; }
[JsonProperty("pressure")]
public double Pressure { get; set; }
[JsonProperty("humidity")]
public double Humidity { get; set; }
[JsonProperty("temp_min")]
public double MinTemperature { get; set; }
[JsonProperty("temp_max")]
public double MaxTemperature { get; set; }
}
public class Wind
{
[JsonProperty("speed")]
public double Speed { get; set; }
[JsonProperty("deg")]
public double WindDirectionDegrees { get; set; }
}
public class Clouds
{
[JsonProperty("all")]
public int CloudinessPercent { get; set; }
}
public class WeatherRoot
{
[JsonProperty("coord")]
public Coord Coordinates { get; set; }
[JsonProperty("sys")]
public Sys System { get; set; }
[JsonProperty("weather")]
public List<Weather> Weather { get; set; }
[JsonProperty("main")]
public Main MainWeather { get; set; }
[JsonProperty("wind")]
public Wind Wind { get; set; }
[JsonProperty("clouds")]
public Clouds Clouds { get; set; }
[JsonProperty("id")]
public int CityId { get; set; }
[JsonProperty("name")]
[Key]
public string Name { get; set; }
[JsonProperty("dt_txt")]
public string Date { get; set; }
[JsonIgnore]
public string DisplayDate => DateTime.Parse(Date).Hour.ToString();
[JsonIgnore]
public string DisplayTemp => $"{MainWeather?.Temperature ?? 0}°
{Weather?[0]?.Main ?? string.Empty}";
[JsonIgnore]
public string DisplayIcon => $"http://openweathermap.org/img/w/{Weather?
[0]?.Icon}.png";
[JsonIgnore]
public string Icon => Weather?[0]?.Icon;
//[JsonIgnore]
//public string DisplayDescription => $"{Weather?[0]?.Description}";
}
But when I am trying to delete a specific object:
public void SaveWeather(WeatherRoot weather)
{
using (var db = new DbContextWeather1())
{
db.Database.CreateIfNotExists();
//var tmp = db.Weathers;
if (db.Weathers.Any(W => W.Name.Equals(weather.Name)))
{
var bye = (from x in db.Weathers
where x.Name.Equals(weather.Name)
select x).FirstOrDefault();
db.Weathers.Remove(bye);
db.Entry(bye).State = System.Data.Entity.EntityState.Deleted;
}
var w = new WeatherRoot()
{
CityId = weather.CityId,
Clouds = weather.Clouds,
Coordinates = weather.Coordinates,
Date = weather.Date,
MainWeather = weather.MainWeather,
Name = weather.Name,
System = weather.System,
Weather = weather.Weather,
Wind = weather.Wind
};
if (w.Date == null)
{
w.Date = DateTime.Now.ToString();
}
db.Weathers.Add(w);
db.SaveChanges();
}
}
I get this error:
The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.Weathers_dbo.WeatherRoots_WeatherRoot_Name". The conflict occurred in database "WeatherApp.DataProtocol.DbContextWeather1", table "dbo.Weathers", column 'WeatherRoot_Name'.
The statement has been terminated.
I tried to google it, but only found related keys, which is not my case.
Does anyone can help me with this, I kind of helpless.
Thanks.
This happens due to a foreign-key constraint. You have to remove all the referenced child records before deleting the parent record.
Try to apply the following code after modifying it according to your business logic and let EF deal with it.
modelBuilder.Entity<Parent>()
.HasMany<Child>(c => c.Children)
.WithOptional(x => x.Parent)
.WillCascadeOnDelete(true);
If you are not sure about how the relationships are made, please observe the tables using SQL Server and examine Keys and Constraints as follows
From the MSDN page on DbSet.Remove:
"Marks the given entity as Deleted such that it will be deleted from the database when SaveChanges is called. Note that the entity must exist in the context in some other state before this method is called."
https://msdn.microsoft.com/en-us/library/system.data.entity.dbset.remove(v=vs.113).aspx
You could try adding:
db.SaveChanges();
under your call:
db.Weathers.Remove(bye);
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