how to write a recursive function for delete nested folder - c#

I have got a task to delete the hierarchy of folders. When i am deleting a folder, the respective sub folders should be deleted.
public ActionResult DeleteLabel(int id)
{
var query = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == id).ToList();
foreach(var item in query)
{
var query1 = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == item.LabelId).ToList();
dbPanAgroDMSContext.LabelMaster.Remove(item);
foreach (var i in query1)
{
dbPanAgroDMSContext.LabelMaster.Remove(i);
}
}
LabelMaster label = dbPanAgroDMSContext.LabelMaster.Find(id);
dbPanAgroDMSContext.LabelMaster.Remove(label);
dbPanAgroDMSContext.SaveChanges();
return Json(new { Result = "OK" });
}
Instead of using repeated for loops I want to do it in a single block of code.Please help me to create a linq query?

Try this
public ActionResult DeleteLabel(int id)
{
Delete(id);
dbPanAgroDMSContext.SaveChanges();
return Json(new { Result = "OK" });
}
private void Delete(int id)
{
//For given id get all child ones first
var query = dbPanAgroDMSContext.LabelMaster.Where(x => x.ParentLabelId == id).ToList();
foreach(var item in query)
{
//for each child ,delet its' childs by calling recursively
Delete(item.Id);
}
LabelMaster label = dbPanAgroDMSContext.LabelMaster.Find(id);
dbPanAgroDMSContext.LabelMaster.Remove(label);
}

Related

Cannot save changes to Database Context

I have a problem saving the changes to Database Context. When i don't save i can see that the listing status is successfully changed , but when i try to save it I get an error which is saying : " There is already an open DataReader associated with this Connection which must be closed first." And i don't know where that comes from. When i try to do it asynchronous i get the same error.
AdministratorController.cs
[Route("/Admin")]
[ApiController]
public class AdministratorController : Controller
{
private readonly dbContext _dbContext;
public AdministratorController(dbContext dbContext)
{
_dbContext = dbContext;
}
///////////////////////////////////
/// //
/// Accept or Reject Listings //
/// //
//////////////////////////////////
[HttpPost]
[Route("acceptListing/{listingId}")]
[AllowAnonymous]
//[Authorize(Roles="Administrator")]
public ActionResult AcceptList([FromRoute]int listingId)
{
if (!ModelState.IsValid)
{
return BadRequest();
}
if (listingId == null)
{
return NotFound("Listing not found.");
}
foreach (Listing listing in _dbContext.Listings)
{
Console.WriteLine(listing.Status);
if(listing.Id == listingId)
{
if(listing.Status == ListingStatus.Accepted)
{
return BadRequest("Listing already accepted.");
}
else
{
listing.Status = ListingStatus.Accepted;
Console.WriteLine(listing.Status);
_dbContext.SaveChanges();
}
return Ok();
}
}
return BadRequest("Couldn't find right listing.");
}
Rather than looping through all listings looking for the one with the Id you want, just filter and get.
Listing? listing = _dbContext.Listings.FirstOrDefault(l => l.Id == listingId);
if (listing is null)
{
return BadRequest("Couldn't find right listing.");
}
if(listing.Status == ListingStatus.Accepted)
{
return BadRequest("Listing already accepted.");
}
listing.Status = ListingStatus.Accepted;
Console.WriteLine(listing.Status);
_dbContext.SaveChanges();
return Ok();
The problem here is that you are iterating the data being fetched from database and in the same time you are trying to save something from the same context. Quick fix is to use ToList in foreach:
foreach (Listing listing in _dbContext.Listings.ToList())
{
// ..
}
But in general you should not fetch everything from the database to process only one item. Just write query that will filter everything on database side. Something along this lines (not tested):
var listing = _dbContext.Listings.FirstOrDefault(l => l.Id == listingId);
if (listing is null)
{
return NotFound();
}
if (listing.Status == ListingStatus.Accepted)
{
return BadRequest("Listing already accepted.");
}
else
{
listing.Status = ListingStatus.Accepted;
Console.WriteLine(listing.Status);
_dbContext.SaveChanges();
}
return Ok();
change the code like this :
var listings = _dbContext.Listings.Tolist();
foreach (Listing listing in listings)
{
Console.WriteLine(listing.Status);
if(listing.Id == listingId)
{
if(listing.Status == ListingStatus.Accepted)
{
return BadRequest("Listing already accepted.");
}
else
{
listing.Status = ListingStatus.Accepted;
Console.WriteLine(listing.Status);
_dbContext.Update(listing);
_dbContext.SaveChanges();
}
return Ok();
}
}

Use except() to exclude items from List

Trying to use Except to exclude items from a list. However the following code is not working for me i.e. my list still includes the records that it should exclude. Is there anything obvious that I am doing wrong? Is there an issue with my loops? BTW the inverse of this code works i.e correct record is inserted when RunTime matches.
[HttpPost]
public JsonResult InsertActivities([FromBody] List<MemberData> customers)
{
var mData =_context.MemberData.Select(x => x.RunTime).ToList();
foreach (var item in mData)
{
var exclude = customers.Where(x => x.RunTime == item).ToList();
var list = customers.Except(exclude).ToList();
foreach (var data in list)
{
_context.MemberData.Add(data);
}
}
int insertedRecords = _context.SaveChanges();
return Json(insertedRecords);
}
Firstly be sure you have model design like below:
public class MemberData:IEquatable<MemberData>
{
public int Id { get; set; }
public string RunTime { get; set; }
public bool Equals(MemberData other)
{
if (other is null)
return false;
return this.RunTime == other.RunTime;
}
public override bool Equals(object obj) => Equals(obj as MemberData);
public override int GetHashCode() => (RunTime).GetHashCode();
}
Then change your code like below:
public JsonResult InsertActivities([FromBody] List<MemberData> customers)
{
//hard-coded the value...
//customers = new List<MemberData>()
//{
// new MemberData(){RunTime="aa"},
// new MemberData(){RunTime="bb"},
// new MemberData(){RunTime="ee"},
//}; //hard-coded the value...
var mData = _context.MemberData.ToList();
var list = customers.Except(mData);
foreach (var item in list)
{
foreach (var data in list)
{
_context.MemberData.Add(data);
}
}
int insertedRecords = _context.SaveChanges();
return Json(insertedRecords);
}
Note:
For inserting data to database successfully, if your model contains primary key, be sure the data's(after did Except operation) keys are not duplicated with the existing database data. Or you can just do like what I did in above code that do not set value for primary key.

c# How to Recursively delete objects and its children

This is my function that gives me a list of nodes based on its parentId:
public List<RepositoriesListViewModel> GetChildren(string ParentId)
{
List<RepositoriesListViewModel> data = new List<RepositoriesListViewModel>();
List<RepositoriesListViewModel> initialData = new List<RepositoriesListViewModel>();
var List = dbContext.Repositories.ToList();
foreach (var item in List)
{
initialData.Add(new RepositoriesListViewModel
{
id = item.Id,
parent = item.ParentId,
ApplicationsId = item.ApplicationsId,
text = item.Name,
Path = item.Path,
CreatedOn = item.CreatedOn
});
};
foreach (RepositoriesListViewModel child in initialData.Where(x => x.parent == ParentId))
{
child.Children = GetChildren(child.id);
data.Add(child);
}
return data;
}
I was wondering if it were possible to delete an item and its children using this function as well? Where would I add my delete call?
This is what my delete call looks like:
public void Delete(string Input)
{
try
{
var repo = Get(Input);
dbContext.Repositories.Remove(repo);
dbContext.SaveChanges();
logger.LogInformation(LoggingGlobals.Delete + " Repository: " + repo.Name);
}
catch (Exception e)
{
logger.LogError(e, "Failed to delete Repository");
}
}
It seems you want something like this:
public void Delete(string Input)
{
try
{
var children = GetChildren(Input);
foreach(var child in children)
{
Delete(child.Id);
}
var repo = Get(Input);
dbContext.Repositories.Remove(repo);
dbContext.SaveChanges();
logger.LogInformation(LoggingGlobals.Delete + " Repository: " + repo.Name);
}
catch (Exception e)
{
logger.LogError(e, "Failed to delete Repository");
}
}
So Before you delete the item itself, you first delete its children and their children.

Remove duplicate rows mvc

I have this method
Meeting is a class
Attendees is an ICollection in Meeting
Class
public partial class Meeting
{
public Meeting()
{
this.Attendees = new List<Attendees>();
}
public virtual ICollection<Attendees> Attendees{ get; set; }
[...]
Method Controller
private void RemoveRowsDuplicated(Meeting model)
{
if (model.Attendees != null)
{
foreach (var item in model.Attendees.GroupBy(x => x.UserName).Select(y => y.Last()))
{
context.Attendees.Remove(item);
}
}
}
The objective is remove duplicate Attendees with the same username in the table.
But the current method it deletes all records and keeps the duplicate
Where am I going wrong?
Correct version of your method will look like this:
private static void RemoveRowsDuplicated(Meeting model)
{
if (model.Attendees != null)
{
var duplicates = new List<Attendees>();
foreach (var item in model.Attendees.GroupBy(x => x.UserName).Where(x=>x.Count()>1))
{
duplicates.AddRange(item.Skip(1));
}
duplicates.ForEach(x=>context.Attendees.Remove(x));
}
}
You can try writing raw SQL and invoking via EF and return Attendees objects in a list.
var query = "Select * from Attendees group by username";
var attendeesList = dbContext.Database.SqlQuery<Attendees>(query).ToList<Attendees>();
As I can see you grouped elements by name and remove last item. So you remove unique elements.
Like this
private void RemoveRowsDuplicated(Meeting model)
{
if (model.Attendees != null)
{
var temporaryAtendees = new List<Attendees>();
foreach(var item in model.Attendees)
{
if (temporaryAtendees.Contains(item))
{
context.Attendees.Remove(item);
}
else
{
temporaryAtendees.Add(item);
}
}
}
}

Linq To Sql using AttachAll. DuplicateKeyException

I searched for the answer on the website but I did not find one. I have the following problem ...
I'm trying to update multiple records in the database as follows:
public void SaveJItem(List<DataForDespatcher> Jitem)
{
JitemsTable.InsertAllOnSubmit(Jitem.Where(i => i.Id ==0));
JitemsTable.AttachAll(Jitem.Where(i => i.Id != 0));
JitemsTable.Context.Refresh(RefreshMode.KeepCurrentValues, Jitem);
JitemsTable.Context.SubmitChanges();
}
The table is described as follows:
[Table(Name = "tanks")]
public class DataForDespatcher
{
[Column(IsPrimaryKey = true, IsDbGenerated = true,AutoSync = AutoSync.OnInsert)]
public int Id { get; set; }
/*bla bla bla */
}
When I update I get the error:
"DuplicateKeyException" in "JitemsTable.AttachAll(Jitem.Where(i => i.Id != 0));".
How do I correctly update the data?
ADD:
razor update form:
#inherits WebViewPage<IEnumerable<DomainModel.Entities.DataForDespatcher>>
/*bla bla bla*/
data controller save(get):
public ViewResult EditForDispatcher(int group)
{
var list = DataRep.JItems.Where(x => x.group == group).Select(x => x);
return View(list);
}
data controller save(post):
[HttpPost]
public ActionResult EditForDispatcher(List<DataForDespatcher> Jitem, string addNewOperation, string sendParam, string operations)
{
if (ModelState.IsValid)
{
int group = DataRep.JItems.ToList().Max(x => x.group + 1);
if (Jitem.Any(x => x.group != 0))
foreach (var dataForDespatcher in Jitem)
dataForDespatcher.group = Jitem.Where(x=>x.group!=0).Select(x=>x.group).First();
else
foreach (var dataForDespatcher in Jitem)
dataForDespatcher.group = group;
DataRep.SaveJItem(Jitem);
}
return View(Jitem);
}
I mean exception is occur because you have both an updated and new items in List and the first in the list is not inserted item. I think, you must do somethong like this:
JitemsTable.InsertAllOnSubmit(Jitem.Where(i => i.Id ==0));
JitemsTable.AttachAll(Jitem.Where(i => i.Id != 0));
JitemsTable.Context.Refresh(RefreshMode.KeepCurrentValues, Jitem);
JitemsTable.Context.SubmitChanges();

Categories