issue when adding an item to a many to many relationship .net core - entity-framework

i have a course management app and i have an issue when i try to add a student to a course studentsList.
when save changes run the student list changes from a list which contains old elements+ the new element to a list with only the new element (the last student added) and then saves it to database.
using EntityFramework 5.0.0
relationship declaration and seeding in context OnModelCreating()
modelBuilder.Entity<Course>().HasMany<Student>(c => c.StudentsList).WithMany(s => s.Courses).UsingEntity(t => t.HasData(
new { CoursesCourseId = Convert.ToInt64(1), StudentsListStudentId="id1"},
new { CoursesCourseId = Convert.ToInt64(1), StudentsListStudentId="id2"},
new { CoursesCourseId = Convert.ToInt64(1), StudentsListStudentId="id3"}
));
models
public class Course
{
public long CourseId { get; set; }
public string CourseName { get; set; }
public IEnumerable<Lesson> LessonsList { get; set; }
public DateTime CourseStartDate { get; set; }
public DateTime CourseEndDate { get; set; }
public List<Student> StudentsList { get; set; }
public class Student
{
[Key]
public string StudentId { get; set; }
public List<Course> Courses { get; set; }
}
controller action
[HttpPatch("{id}")]
public async Task<IActionResult> RegisterStudentToCourse(long id, [FromBody] List<string> studentsIds)
{
Course course = await _courseRepo.GetCourse(id);
if (course == null || !studentsIds.Any())
return BadRequest();
IEnumerable<Lesson> list = await _lessonRepo.GetLessons(id);
List<Lesson> lessonsList = list.ToList();
List<Student> studentsList = course.StudentsList.ToList();
foreach (string studentId in studentsIds)
{
Student student = _studetRepo.GetStudent(studentId);
if (student == null)
return BadRequest();
if (studentsList.Contains(student))
continue;
//HERE IS THE CALL TO THE REPOSITORY ADDSTUDENT
await _courseRepo.AddStudent(id, studentId);
foreach (Lesson l in lessonsList)
{
Attendance attendance = await _attendanceRepo.CreateAttandance(studentId);
await _lessonRepo.AddAttendance(l.LessonId, attendance);
}
}
_context.SaveChanges();
return Ok();
}
repository function
public async Task<bool> AddStudent(long id, string studentId)
{
Course course = await _context.Courses.Include(c => c.StudentsList).FirstOrDefaultAsync(c => c.CourseId == id);
Student student = await _context.Students.FirstOrDefaultAsync(s => s.StudentId == studentId);
if (course == null || student==null)
return false;
course.StudentsList.Add(student);
return await _context.SaveChangesAsync() > 0;
}

Related

In C# mongodb, match the entire external List of Objects to the Child list of the Parent list

`Suppose, I've User list with list of order
User model
`public class User
{
public int Id { get; set; }
public string Name { get; set; }
public List<UserOrder> Orders { get; set; }
}`
User Order model
`public class UserOrder
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
}`
Order model
`public class Order
{
public int Name { get; set; }
public decimal Price { get; set; }
}`
Here, I want to retrieve all user list that contain all element of List in UserOrder list. (Compare with Name and Price)`
I don't quite understand what you mean, do you want to include the current Orders list when querying User?
You need to link the two tables. For example, add a field UserId to the UserOrder model to associate with User; or add a List<int> to the User model to store the corresponding UserOrderId.
I made a simple test, you can refer to it. In order to facilitate maintenance, I will write the method of processing data from the database in a separate service:
User Model:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public List<int> UserOrderIds { get; set; }
public List<UserOrder> Orders { get; set; }
}
UserService:
public class UserService
{
private readonly IMongoCollection<User> _users;
public UserService(IUserDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_users = database.GetCollection<User>(settings.UserCollectionName);
}
public async Task<List<User>> GetAllAsync()
{
return await _users.Find(s => true).ToListAsync();
}
public async Task<User> GetByIdAsync(int id)
{
return await _users.Find<User>(s => s.Id == id).FirstOrDefaultAsync();
}
public async Task<User> CreateAsync(User user)
{
await _users.InsertOneAsync(user);
return user;
}
public async Task UpdateAsync(int id, User user)
{
await _users.ReplaceOneAsync(s => s.Id == id, user);
}
public async Task DeleteAsync(int id)
{
await _users.DeleteOneAsync(s => s.Id == id);
}
}
UserOrderService:
public class UserOrderService
{
private readonly IMongoCollection<UserOrder> _userOrders;
public UserOrderService(IUserDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_userOrders = database.GetCollection<UserOrder>(settings.UserOrderCollectionName);
}
public async Task<List<UserOrder>> GetAllAsync()
{
return await _userOrders.Find(s => true).ToListAsync();
}
public async Task<UserOrder> GetByIdAsync(int id)
{
return await _userOrders.Find<UserOrder>(c => c.Id == id).FirstOrDefaultAsync();
}
public async Task<UserOrder> CreateAsync(UserOrder userOrder)
{
await _userOrders.InsertOneAsync(userOrder);
return userOrder;
}
public async Task UpdateAsync(int id, UserOrder userOrder)
{
await _userOrders.ReplaceOneAsync(c => c.Id == id, userOrder);
}
public async Task DeleteAsync(int id)
{
await _userOrders.DeleteOneAsync(c => c.Id == id);
}
}
appsetting.json:
"UserDatabaseSettings": {
"UserCollectionName": "User",
"UserOrderCollectionName": "UserOrder",
"ConnectionString": "mongodb://localhost:27017",
"DatabaseName": "TestDb"
}
IUserDatabaseSettings(Used to obtain database related information):
public interface IUserDatabaseSettings
{
string UserCollectionName { get; set; }
string UserOrderCollectionName { get; set; }
string ConnectionString { get; set; }
string DatabaseName { get; set; }
}
public class UserDatabaseSettings : IUserDatabaseSettings
{
public string UserCollectionName { get; set; }
public string UserOrderCollectionName { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
}
Registration service:
services.Configure<UserDatabaseSettings>(
Configuration.GetSection(nameof(UserDatabaseSettings)));
services.AddSingleton<IUserDatabaseSettings>(provider =>
provider.GetRequiredService<IOptions<UserDatabaseSettings>>().Value);
services.AddSingleton<UserService>();
services.AddSingleton<UserOrderService>();
Controller:
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
private readonly UserService _userService;
private readonly UserOrderService _userOrderService;
public UserController(UserService sService, UserOrderService cService)
{
_userService = sService;
_userOrderService = cService;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<User>>> GetAll()
{
var users = await _userService.GetAllAsync();
return Ok(users);
}
[HttpGet("{id}")]
public async Task<ActionResult<User>> GetById(int id)
{
var user = await _userService.GetByIdAsync(id);
if (user == null)
{
return NotFound();
}
if (user.UserOrderIds.Count > 0)
{
var tempList = new List<UserOrder>();
foreach (var userOrderId in user.UserOrderIds)
{
var userOrder = await _userOrderService.GetByIdAsync(userOrderId);
if (userOrder != null)
tempList.Add(userOrder);
}
user.Orders = tempList;
}
return Ok(user);
}
[HttpPost]
public async Task<IActionResult> Create(User user)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
await _userService.CreateAsync(user);
return Ok(user);
}
[HttpPut]
public async Task<IActionResult> Update(int id, User updatedUser)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
var queriedStudent = await _userService.GetByIdAsync(id);
if (queriedStudent == null)
{
return NotFound();
}
await _userService.UpdateAsync(id, updatedUser);
return NoContent();
}
[HttpDelete]
public async Task<IActionResult> Delete(int id)
{
var student = await _userService.GetByIdAsync(id);
if (student == null)
{
return NotFound();
}
await _userService.DeleteAsync(id);
return NoContent();
}
}
Test Result:
Complete example is here.

EF Core 6 updated data retrieve problem with multiple repositories

I am working on a Blazor Server Application that has a Radzen master-detail data grid. This data grid is populated with IsActive = 1 data OnInitializedAsync method.
Here is the Order repository and related query which retrieves active data:
namespace IMS.Plugins.EFCore
{
public class OrderRepository : IOrderRepository
{
private readonly IMSContext _db;
public OrderRepository(IMSContext db)
{
_db = db;
}
public async Task<IEnumerable<Order?>> GetAllOrders(ClaimsPrincipal user)
{
if (user.IsInRole("Administrators"))
{
return await _db.Orders.Include(d => d.OrderDetails.Where(od => od.IsActive == 1)).ThenInclude(v => v.Vendor).ToListAsync();
}
return await _db.Orders.Include(d => d.OrderDetails.Where(od => od.IsActive == 1)).ThenInclude(v => v.Vendor).ToListAsync();
}
}
}
Here is the Detail repository which sets the related order detail to IsActive = 0
namespace IMS.Plugins.EFCore
{
public class OrderDetailRepository : IOrderDetailRepository
{
private readonly IMSContext _db;
public OrderDetailRepository(IMSContext db)
{
_db = db;
}
public async Task PassiveOrderDetailAsync(OrderDetail orderDetail)
{
var detail = await this._db.OrdersDetail.FindAsync(orderDetail.Id);
if (detail != null)
{
detail.IsActive = 0; // 0-Passive
await _db.SaveChangesAsync();
}
}
}
}
Here is the master-detail data grid populated OnInitializedAsync method. By the way, this part is working. (gets IsActive = 1)
protected override async Task OnInitializedAsync()
{
user = (await _authenticationStateProvider.GetAuthenticationStateAsync()).User;
//userName = user.Identity.Name;
if (!user.Identity.IsAuthenticated)
{
NavigationManager.NavigateTo("/Identity/Account/Login", false);
}
_orders = await ViewAllOrdersUseCase.ExecuteAsync(user);
SelectedOrders = new List<Order?> { _orders.FirstOrDefault() };
_vendors = await ViewAllVendorsUseCase.ExecuteAsync();
_customers = await ViewAllCustomersUseCase.ExecuteAsync();
}
The problem starts when I try to update a detail to IsActive = 0 as shown on the screenshot.
Related Blazor:
<RadzenButton Icon="delete" ButtonStyle="ButtonStyle.Danger" Class="m-1" Click="#(args => PassiveDetail(detail))">
</RadzenButton>
Here is what I do in the related portion:
RadzenDataGrid<OrderDetail> _gridDetail;
IEnumerable<Order?> _orders = new List<Order?>();
...
async Task PassiveDetail(OrderDetail orderDetail)
{
if (orderDetail == _detailToInsert)
{
_detailToInsert = null;
}
await _gridDetail.UpdateRow(orderDetail);
await PassiveOrderDetailUseCase.ExecuteAsync(orderDetail);
_orders = await ViewAllOrdersUseCase.ExecuteAsync(user);
StateHasChanged();
}
Selected row updated successfully but when this line calls _orders = await ViewAllOrdersUseCase.ExecuteAsync(user); it still gets the old data IsActive = 0. I couldn't find out why? However, OnInitializedAsync method works as excepted. Frankly, I couldn't solve.
Edit 1
Is it because there are 2 separate repositories for both order and order details? They are having their own insert and updates?
Edit 2
I should have added earlier Order and OrderDetail entities:
public class Order
{
public int Id { get; set; }
[Required]
public DateTime OrderDateTime { get; set; }
[Required]
[MaxLength(250)]
public int CustomerId { get; set; }
public string Status { get; set; }
[MaxLength(50)]
public string DoneBy { get; set; }
public List<OrderDetail> OrderDetails { get; set; }
public Customer Customer { get; set; }
}
public class OrderDetail
{
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string ProductCode { get; set; }
[Required]
[MaxLength(250)]
public string ProductName { get; set; }
[Required]
public int Quantity { get; set; }
[Required]
public double BuyUnitPrice { get; set; }
public double CostRatio { get; set; }
public double UnitCost { get; set; }
public double TotalBuyPrice { get; set; }
public double? SellUnitPrice { get; set; }
public double? TotalSellPrice { get; set; }
[MaxLength(150)]
public string? ShippingNumber { get; set; }
public string? Status { get; set; }
[MaxLength(150)]
public string? TrackingNumber { get; set; }
[MaxLength(400)]
public string? Description { get; set; }
public string? Currency { get; set; }
public string? CustomerStockCode { get; set; }
public string? CustomerOrderNumber { get; set; }
public int IsActive { get; set; }
public double? TotalUnitCost { get; set; }
public int OrderId { get; set; }
public int VendorId { get; set; }
public Order Order { get; set; }
public Vendor Vendor { get; set; }
}
Edit 3
I think I found the suspect. The query below shouldn't get the IsActive=0 but it somehow gets! Any ideas for this situation?
Here is the query:
public async Task<IEnumerable<Order?>> GetAllOrders(ClaimsPrincipal user)
{
if (user.IsInRole("Administrators"))
{
return await _db.Orders.Include(d => d.OrderDetails.Where(od => od.IsActive == 1)).ThenInclude(v => v.Vendor).ToListAsync();
}
return await _db.Orders.Include(d => d.OrderDetails.Where(od => od.IsActive == 1)).ThenInclude(v => v.Vendor).ToListAsync();
}
The record is updated, why is the query doesn't work the way it is expected? First I am updating then I am querying IsActive = 1
await PassiveOrderDetailUseCase.ExecuteAsync(orderDetail); //sets to IsActive = 0
_orders = await ViewAllOrdersUseCase.ExecuteAsync(user); // calls GetAllOrders method above,should get only the actives IsActive = 1
But IsActive = 0 also comes inside of _orders as seen in the screenshot below.
Edit 4
When I add AsNoTracking() the query in my previous post gets only IsActive = 1 that is what I want but somehow doesn't get the Customer which is why I want to include it. Order have 2 children, Customer and OrderDetail. OrderDetail has one, Vendor. Couldn't manage to include Customer tough to the query.
This works so far.
Orders
.Include(d => d.OrderDetails.Where(od => od.IsActive == 1))
.ThenInclude(v => v.Vendor)
.Include(c => c.Customer)
.AsNoTracking()
.ToListAsync();

AutoMapper with EF Core doesn't return OData #count correctly if using $top

I'm using the solution provided by this link: AutoMapper don't work with entity EF Core
My problem is when using $top, #odata.count always return the number informed in $top but should return the number of total record.
I know that ODataQueryOptions has a property “Count”, but I don't know if it's possible to use to solve the problem
I'm using the below the code provided by Дмитрий Краснов in his question including the solution by Ivan Stoev:
There is entities:
public class LessonCatalog {
public string Name { get; set; }
public int? ImageId { get; set; }
public virtual Image Image { get; set; }
public virtual ICollection<Lesson> Lessons { get; set; }
}
public class Lesson {
public string Name { get; set; }
public string Description { get; set; }
public int? ImageId { get; set; }
public virtual Image Image { get; set; }
public int LessonCatalogId { get; set; }
public virtual LessonCatalog LessonCatalog { get; set; }
}
Views:
public class LessonView {
public string Name { get; set; }
public string Description { get; set; }
public int? ImageId { get; set; }
public ImageView Image { get; set; }
public int LessonCatalogId { get; set; }
public LessonCatalogView LessonCatalog { get; set; }
}
public class LessonCatalogView {
public string Name { get; set; }
public int? ImageId { get; set; }
public ImageView Image { get; set; }
public IEnumerable<LessonView> Lessons { get; set; }
}
My maps:
CreateMap<LessonCatalog, LessonCatalogView>()
.ForMember(dest => dest.Image, map => map.ExplicitExpansion())
.ForMember(dest => dest.Lessons, map => map.ExplicitExpansion());
CreateMap<Lesson, LessonView>()
.ForMember(dest => dest.LessonCatalog, map => map.ExplicitExpansion());
In my repository:
protected readonly DbContext _context;
protected readonly DbSet<TEntity> _entities;
public Repository(DbContext context) {
_context = context;
_entities = context.Set<TEntity>();
}
public IEnumerable<TView> GetOData<TView>(ODataQueryOptions<TView> query,
Expression<Func<TEntity, bool>> predicate = null) {
IQueryable<TEntity> repQuery = _entities.AsQueryable();
IQueryable res;
if (predicate != null) repQuery = _entities.Where(predicate);
if (query != null) {
string[] expandProperties = GetExpands(query);
//!!!
res = repQuery.ProjectTo<TView>(Mapper.Configuration, null, expandProperties);
//!!!
var settings = new ODataQuerySettings();
var ofilter = query.Filter;
var orderBy = query.OrderBy;
var skip = query.Skip;
var top = query.Top;
if (ofilter != null) res = ofilter.ApplyTo(res, settings);
if (orderBy != null) res = orderBy.ApplyTo(res, settings);
if (skip != null) res = skip.ApplyTo(res, settings);
if (top != null) res = top.ApplyTo(res, settings);
} else {
res = repQuery.ProjectTo<TView>(Mapper.Configuration);
}
return (res as IQueryable<TView>).AsEnumerable();
}
If my query result has 1007 records, and I use
…$count=true&$top=5
the result for count should be
"#odata.count": 1007
But instead the result is always
"#odata.count": 5
Using SQL Server Profile I can see that the Select for count is including the “top”. So, how to avoid this to happen?
I received a help from the Github Guy (thanks to #Gennady Pundikov) and could now answer this question.
I changed the GetOData Method to get the Count before apply others settings:
public IEnumerable<TView> GetOData<TView>(ODataQueryOptions<TView> query,
Expression<Func<TEntity, bool>> predicate = null) {
IQueryable<TEntity> repQuery = _entities.AsQueryable();
IQueryable res;
if (predicate != null) repQuery = _entities.Where(predicate);
if (query != null) {
string[] expandProperties = GetExpands(query);
//!!!
res = repQuery.ProjectTo<TView>(Mapper.Configuration, null, expandProperties);
//!!!
var settings = new ODataQuerySettings();
var ofilter = query.Filter;
var orderBy = query.OrderBy;
var skip = query.Skip;
var top = query.Top;
if (ofilter != null) res = ofilter.ApplyTo(res, settings);
if (query.Count?.Value == true)
{
// We should calculate TotalCount only with filter
// http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part2-url-conventions.html#_Toc371341773
// 4.8 Addressing the Count of a Collection
// "The returned count MUST NOT be affected by $top, $skip, $orderby, or $expand.
query.Request.ODataFeature().TotalCount = ((IQueryable<TView>)res).LongCount();
}
if (top != null) res = top.ApplyTo(res, settings);
if (orderBy != null) res = orderBy.ApplyTo(res, settings);
if (skip != null) res = skip.ApplyTo(res, settings);
} else {
res = repQuery.ProjectTo<TView>(Mapper.Configuration);
}
return (res as IQueryable<TView>).AsEnumerable();
}

ASP.Net Core EF M-M Instance Cannot be Tracked

Consider the following error:
InvalidOperationException: The instance of entity type 'OrderRegion' cannot be tracked because another instance with the key value '[Orderid: 10, RegionId: 1]' is already being tracked...
Also, consider the following classes (slightly snipped for brevity):
public class Order
…
[Key]
public int Id { get; set; }
…
[Display(Name = "Regions")]
public ICollection<OrderRegion> OrderRegions { get; set; }
[Display(Name = "Stores")]
public ICollection<OrderStore> OrderStores { get; set; }
public class OrderRegion
{
//[Key]
public int OrderId { get; set; }
public Order Order { get; set; }
//[Key]
public int RegionId { get; set; }
public Region Region { get; set; }
}
public class OrderStore
{
//[Key]
public int OrderId { get; set; }
public Order Order { get; set; }
//[Key]
public int StoreId { get; set; }
public Store Store { get; set; }
}
Also of relevance is the Context where I create the relationships:
public class MyContext:DbContext
{
public MyContext(DbContextOptions<AzureOrdersContext> options) : base(options) { }
public DbSet<Order> Order { get; set; }
public DbSet<OrderRegion> OrderRegion { get; set; }
public DbSet<OrderStore> OrderStore { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
…
modelBuilder.Entity<OrderRegion>()
.HasKey(nr => new { nr.OrderId, nr.RegionId });
modelBuilder.Entity<OrderRegion>()
.HasOne(nr => nr.Order)
.WithMany(n => n.OrderRegions)
.HasForeignKey(nr => nr.OrderId);
modelBuilder.Entity<OrderRegion>()
.HasOne(nr => nr.Region)
.WithMany(n => n.OrderRegions)
.HasForeignKey(nr => nr.RegionId);
modelBuilder.Entity<OrderStore>()
.HasKey(nr => new { nr.OrderId, nr.StoreId });
modelBuilder.Entity<OrderStore>()
.HasOne(nr => nr.Order)
.WithMany(n => n.OrderStores)
.HasForeignKey(nr => nr.OrderId);
modelBuilder.Entity<OrderStore>()
.HasOne(nr => nr.Store)
.WithMany(n => n.OrderStores)
.HasForeignKey(nr => nr.StoreId);
}
}
And finally, my "Edit.cshtml.cs" where my error is thrown (snipped a lot):
public async Task<IActionResult> OnPostAsync(int? id, int[] AssignedRegions, int[] AssignedStores)
{
if (!ModelState.IsValid)
{
return Page();
}
var Ordertoupdate = await _context.Order
.Include(i => i.OrderRegions).ThenInclude(navigationPropertyPath: i => i.Region)
.Include(i => i.OrderStores).ThenInclude(navigationPropertyPath: i => i.Store)
.FirstOrDefaultAsync(m => m.Id == id);
...
if (await TryUpdateModelAsync<Web.Models.Order>(
Ordertoupdate,
"Order",
i => i.CreatedOn,
i => i.CreatedBy,
i => i.ModifiedBy, i => i.ExpirationDate,
...))
{
UpdateOrderRegions(_context, AssignedRegions, Ordertoupdate);
UpdateOrderStores(_context, AssignedStores, Ordertoupdate);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
UpdateOrderRegions(_context, AssignedRegions, Ordertoupdate);
UpdateOrderStores(_context, AssignedStores, Ordertoupdate);
PopulateAssignedRegions(_context, Ordertoupdate);
PopulateAssignedStores(_context, Ordertoupdate);
return Page();
}
The error is getting thrown on _context.SaveChangesAsync(); Any ideas? I'm certain I'm just doing something stupid and not seeing a simple fix.
Updating to include UpdateOrderRegions as requested:
public void UpdateOrderRegions (AzureOrdersContext _context, int[] SelectedRegions, Web.Models.Order OrderToUpdate)
{
if (SelectedRegions == null)
{
OrderToUpdate.OrderRegions = new List<OrderRegion>();
return;
}
var StoreRegionsToDelete= OrderToUpdate.OrderRegions.Where<OrderRegion>(nr => {
return !SelectedRegions.AsQueryable<Int32>().Contains<Int32>(nr.RegionId);
});
StoreRegionsToDelete.ToList().ForEach(r => { OrderToUpdate.OrderRegions.Remove(r); });
var StoreRegionsToAdd = SelectedRegions.AsQueryable<Int32>().Where<Int32>(regionId =>
!OrderToUpdate.OrderRegions.Any( nr=> nr.RegionId == regionId)
);
StoreRegionsToAdd.ToList().ForEach(regionId =>
OrderToUpdate.OrderRegions.Add(new OrderRegion
{
OrderId = OrderToUpdate.Id,
RegionId = regionId
}));
////This is where a different, more frustrating logical error lives but isn't related to my EF error
////Attempting to model after: https://github.com/aspnet/Docs/blob/master/aspnetcore/data/ef-rp/intro/samples/cu/Pages/Instructors/InstructorCoursesPageModel.cshtml.cs
var selectedRegionHS = new HashSet<string>(SelectedRegions);
var regionOrders = new HashSet<int>(OrderToUpdate.OrderRegions.Select(c => c.Order.Id));
foreach (var thisregion in _context.Region)
{
if (selectedRegionHS.Contains(thisregion.Id.ToString()))
{
if (!regionOrders.Contains(thisregion.Id))
{
OrderToUpdate.OrderRegions.Add(
new OrderRegion
{
OrderId = OrderToUpdate.Id,
RegionId = thisregion.Id
});
}
}
else
{
if (regionOrders.Contains(thisregion.Id))
{
OrderRegion RegionToRemove = OrderToUpdate.OrderRegions.SingleOrDefault(i => i.RegionId == thisregion.Id);
_context.Remove(RegionToRemove);
}
}
}
}
This issue occurs when the context already has an item tracked and you explicitly try attaching a new object with the same key.
Considering the error is on OrderRegion and this type has a composite key of OrderId/RegionId, I think it is likely that you are retrieving the OrderRegion and attaching a new OrderRegion with the same OrderId/RegionId combination. You may need to check if an OrderRegion key already exists or clear the Order's regions and rebuild the list to avoid this collision.
I hope this points you in the right direction. Feel free to provide the code where you handle the OrderRegion updates and I'll try to further assist.

Update related data when AutoDetectChangesEnabled = false

I'm trying to update a simple model:
public class DayOff
{
public int Id { get; set; }
public List<User> Users { get; set; }
public DayOff()
{
Users = new List<User>();
}
}
my service layer is:
public void Update(DayOff dayOff, IEnumerable<int> users)
{
var dayOffToUpdate = _db.DayOff.Include("Users").Single(d => d.Id == dayOff.Id);
dayOffToUpdate.Users.Clear();
_db.Entry(dayOffToUpdate).CurrentValues.SetValues(dayOff);
dayOffToUpdate.Users = _db.User.Where(u => users.Contains(u.Id)).ToList();
foreach (var user in dayOffToUpdate.Users)
{
_db.Entry(user).State = EntityState.Modified;
}
_db.SaveChanges();
}
but it is NOT updating the users, so how can I?