How to clone object with a different Primary Key - c#

I have this class Cart_Record, shown below. I want to update the PrimaryKey. To do that I am trying to clone the object into a new object to copy CartLines and update ID. I haven't found much in the issue queue or the documentation to help me.
public class Cart_Record : RealmObject
{
public Cart_Record() { }
public Cart_Record(IList<Cart_Line> cartLines, int id)
{
ID = id;
foreach (var cartLine in cartLines)
CartLines.Add(App.RealmDB.Find<Cart_Line>(cartLine.ProductId));
}
[PrimaryKey]
public int ID { get; set; }
public IList<Cart_Line> CartLines { get; }
}
I am trying this
var appCart = App.RealmDB.All<Cart_Record>().First();
App.RealmDB.Write(() =>
{
var cartLines = new List<Cart_Line>(appCart.CartLines);
App.RealmDB.Remove(App.RealmDB.Find<Cart_Record>(appCart.ID));
App.RealmDB.Add<Cart_Record>(new Cart_Record(cartLines, serverCart.ID));
});
However I keep getting exceptions, specifically RealmObjectManagedByAnotherRealmException. I don't understand how as I am not readding the Cart_Line objects to Realm, just to the CartLine list in the new object.
What am I doing wrong?
Thanks ahead of time.
Edit: I found something that works but I would like to see if someone else have a better method. This is what works for me.
var appCart = App.RealmDB.All<Cart_Record>().First();
App.RealmDB.Write(() =>
{
var cartLines = new List<Cart_Line>(appCart.CartLines);
App.RealmDB.Remove(App.RealmDB.Find<Cart_Record>(appCart.ID));
var newAppCart = App.RealmDB.Add<Cart_Record>(new Cart_Record() { ID = serverCart.ID });
foreach (var cartLine in cartLines)
newAppCart.CartLines.Add(cartLine);
});

I'm not sure what App.RealmDB does under the hood, but using the out-of-the-box Realm API, what you want to achieve can be done by simply adding the CartLines from the original to the updated object:
// Assume want to change Id from 1 to 2
var realm = Realm.GetInstance();
var original = realm.Find<Cart_Record>(1);
var updated = new Cart_Record { ID = 2 }; // other properties must be copied here
foreach (var cart in original.CartLines)
{
updated.CartLines.Add(cart);
}
realm.Write(() =>
{
realm.Remove(original);
realm.Add(updated);
});
// updated now has all the original's CartLines

Related

C# Change selected object from a list without changing the original list

Here I've selected the record which a want to get into a new variable. and after that, when I'm changing the value of 'itm.note' it's automatically modifying the original list (Obj.Testlist) as well. How can this be avoided? Only want to change 'itm' object and Obj.Testlist list should be keep as it is.
var itm = Obj.Testlist.Where(x => x.id == 1).SingleOrDefault();
itm.note = "text";
You could clone the fetched item, but that wouldn't be efficient.
How about this:
var changedFetchedItem = Obj.Testlist.Where(x => x.id == 1)
.Select(x => new
{
Id = 1,
Note = "text",
// copy the other properties that you plan to use
// don't copy the ones that you don't use.
}
.SingleOrDefault();
Since you will be fetching at utmost one item, this is very efficient.
I chose to create an object with anonymous type. If you need a specific type, you can add the type after the keyword new
Since I have large model, decided to use cloning for this (Sample code),
public class TestClone : ICloneable
{
public bool IsSuccess { get; set; }
public string Note { get; set; }
public string ErrorDetail { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
static void Main(string[] args)
{
var test1 = new TestClone() { IsSuccess = true, Note= "text", ErrorDetail = "DTL1" };
var test2 = (TestClone) test1.Clone();
test2.Note= "new text";
}

Why isn't my object being updated

I'm doing something wrong because after the loop executed myData still contains objects with blank ids. Why isn't the myData object being updated in the following foreach loop, and how do I fix it?
I thought it could be that I wasn't passing the object by reference, but added a ref keyword and also moved to the main method and I'm still showing the object not being updated.
Additional Information
The user object in the foreach loop is being updated, but the myData list does not reflect the updates I see being applied to the user object.
** Solution **
I was not creating a List but an Enumerable which was pulling the json each time I went through myData in a foreach list. Adding a ToList() fixed my issue.
public class MyData
{
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
int index = 0;
// Does not allow me to up, creates an IEnumerable
//IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
// .Select(x => new MyData()
// {
// ID = x["id"].ToString(),
// Properties = x.OfType<JProperty>()
// .ToDictionary(y => y.Name, y => y.Value.ToString())
// });
//Works allows me to update the resulting list.
IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
.Select(x => new MyData()
{
ID = x["id"].ToString(),
Properties = x.OfType<JProperty>()
.ToDictionary(y => y.Name, y => y.Value.ToString())
}).ToList();
foreach (var user in myData) // Also tried myData.ToList()
{
if (string.IsNullOrEmpty(user.ID))
{
user.ID = index.ToString();
user.Properties["id"] = index.ToString();
}
index++;
}
public class MyData
{
public MyData()
{
this.Properties = new Dictionary<string,string>();
}
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public static void Main(string[] args)
{
IEnumerable<MyData> myDataList = new List<MyData>();
int index = 0; // Assuming your starting point is 0
foreach (var obj in myDataList)
{
if (obj != null && string.IsNullOrEmpty(obj.ID))
{
obj.ID = index.ToString();
// Checks if the Properties dictionary has the key "id"
if (obj.Properties.ContainsKey("id"))
{
// If it does, then update it
obj.Properties["id"] = obj.ID;
}
else
{
// Else add it to the dictionary
obj.Properties.Add("id", obj.ID);
}
}
index++;
}
I believe the reason why your objects are not updating because it's probably still referring to the memory block before your objects were changed. Perhaps. The easiest way (that I can think of, there are thousands of smarter programmers than me) is to create a new list and have it contain all of your updated objects.
Edit
I updated the code above with the code that I have. I created a method to set a small amount of objects to test:
private static IEnumerable<MyData> GetMyData()
{
return new List<MyData>()
{
new MyData(),
new MyData() {ID = "2"},
new MyData() {ID = "3"},
new MyData()
};
}
I was able to view my changes and then go through a foreach loop to view my changes. If the ID of the object is Null or Empty, then it steps into the if check and adds the current index to the ID as you know.
Now for my question: Which "id" is blank? The "id" in the dictionary or is it the ID of the model? Are all of your (Model).ID blank? As the updated code of yours, if your dictionary doesn't have "id" as a key, it's going to throw an exception saying it doesn't exist so you will need to do a check to make sure it does exist or add it if it doesn't.

C# Traverse Hierarchy without Recursion

I need a hand to transform my recursive function into a loop as I'm stuck trying to do this for hours. The reason is that I kept running into StackOverflow exception.
Please check the following code:
private List<int> GetManagers(Employee employee, List<Employee> employeeList)
{
List<int> collection = new List<int>();
if (employee.DirectManagers.Any())
{
var managers = employeeList.Where(x => employee.DirectManagers.Any(y => y.Equals(x.Id)));
foreach (var manager in managers)
{
if (!collection.Any(x => x.Equals(manager.Id)))
collection.Add(manager.Id);
if (manager.DirectManagers.Any())
collection.AddRange(GetManagers(manager, employeeList));
}
}
return collection;
}
Edit: More codes here
foreach (var employee in employeeList)
{
List<int> allManagers = new List<int>();
allManagers = GetManagers(employee, employeeList);
// Do something with allManagers found here that does not affect the collection
}
public class Employee
{
public int Id { get; set; }
public int? DepartmentId { get; set; }
public List<int> DirectManagers { get; set; }
public List<int> DirectSubordinates { get; set; }
public int Counter { get; set; }
}
var employeeList = context.AdministratorProfiles
.Where(x => !x.dateResigned.HasValue && x.departmentID.HasValue)
.Select(x => new Employee {
Id = x.id,
DepartmentId = x.departmentID,
Counter = 0,
DirectManagers = x.Managers.Select(y => y.managerID).ToList(),
DirectSubordinates = x.Subordinates.Select(y => y.adminID).ToList()
}).ToList(); // TODO: Add active account here
Basically, what this does is that I'm trying to get all the managers of an Employee. Due to the huge number of staff, I often run into StackOverflow exception. I need a hand, appreciate if anyone out there could lend a hand. Thank you.
Edit: Now, I have listed all the codes. So perhaps you can have a better understanding. Basically, what I'm trying to do is to loop through every single employee to perform work, first I must have a work list. This work list would exclude all the managers or managers' managers to form the final list.
Your problem is not recursion but cyclic references. You can use pattern visitor to work with this problem. (In this pattern you mark all entities that were visited with your recursion method and if you visit this entity again, you just return)
You could do something like:
...
Dictionary<int, bool> processed = new Dictionary<int, bool>();
Queue<Employee> managersQueue = new Queue<Employee>();
managersQueue.Enqueue(employee);
while (managersQueue.Any())
{
var currentEmployee = stack.Dequeue();
var managers = employeeList.Where(x => currentEmployee.DirectManagers.Any(y => y.Equals(x.Id)));
foreach (var manager in managers)
{
if (processed.ContainsKey(manager.Id)) continue;
processed.Add(manager.Id, true);
managersQueue.Enqueue(manager);
}
}
return processed.Select(x => x.Key).ToList();
This is just a basic outline of how you could do this iteratively, obviously I don't know your code base or exactly how certain calls would be made.

Issue with list in C# -- MVC

I have issue in the following code. Below is my model code
public class Comments
{
public string displayComments { get; set; }
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")]
public DateTime? dTime { get; set; }
public int airPortId { get; set; }
}
public class LstComments
{
private List<Comments> _lstcomment = new List<Comments>();
public List<Comments> lstCommet
{
get
{
return _lstcomment;
}
set
{
_lstcomment = value;
}
}
}
and in mycontroller am getting data from EF and adding it to the properties in For loop. Code Below
Comments com = new Comments();
LstComments savedComments = new LstComments();
AirportEntities airPortEntity = new AirportEntities();
var userComments = from c in airPortEntity.AirportComments
select c;
//List<Comments> savedComments = new List<Comments>();
foreach (var item in userComments)
{
com.displayComments = item.Comments;
com.dTime = item.Time;
savedComments.lstCommet.Add(com);
}
My issue is my entire list is getting updated with same records(recently added data)
For eg. foreach 3rd timn updates both 1st and 2nd 3rd item in list with 3rd item data.
What i am doing wrong ?
You instantiate Comments outside of the loop. This means there are a bunch of references to the same comment object on the heap. You need to do
Comments com = new Comments(); inside of the foreach. This will create a separate instance on each iteration, instead of just giving the one instance new values.
you need to instantiate Comments com = new Comments(); each time in foreach. As for now you just rewrite reference to the same object.
Or which is better to rewrite foreach as:
foreach (var item in userComments)
{
savedComments.lstCommet.Add(
new Comments()
{
com.displayComments = item.Comments,
com.dTime = item.Time
});
}

How to check for duplicates before saving?

I'm having a heck of a time figuring out how to add entities like this to my db.
public class ThingWithListings
{
public virtual ICollection<Listing> Listings;
}
public class Listing
{
public int Id;
public virtual ListingData Data { get; set; } // has a FK to ListingData
public DateTime Creation { get; set; }
}
public class ListingData
{
public int listing_id; // PK
....
}
I'm retrieving a 'ThingWithLIstings' from another source and writing it to my db. The tricky part is that any number of Listings may report to the same ListingData. So when I add or update a ThingWithListings, I need to see if a ListingData already exists and if so, just use that one.
I'm new to EF, so I've been using the AddOrUpdate from Author Vickers' article here: Obviously, this doesn't work for this scenario and so I've tried for a day or so to figure out the right way to do this. I'll spare you all the story of my main failed attempts and hope someone can just tell me the right way to do this.
if (DatabaseContext.ListingData.Any(l => l.listing_id == myId))
{
//already exists
}
else
{
//do whatever
}
var newArrivals = new ThingWithListings();
newArrivals.Listings = new List<Listing>();
newArrivals.Listings.Add(
new Listing()
{
creation = DateTime.Now,
ListingData = new ListingData()
{
listing_id = 1
}
});
//another Listing with the same ListingData listing_id
newArrivals.Listings.Add(
new Listing()
{
creation = DateTime.Now,
ListingData = new ListingData()
{
listing_id = 1
}
});
//dummy id generator
int counter = 1;
using (var ctx = new Database1Entities())
{
//get the ListingData from the current db context
var dbListingData = ctx.ListingData;
// the new arrivals
foreach (Listing item in newArrivals.Listings)
{
//get the listing_id of a new arrival's ListingData
int id = item.ListingData.listing_id;
//get the ListingData from the db, if it exists
var listingDataFromDb = dbListingData.FirstOrDefault(i => i.listing_id == id);
//if not, create it and add it to the db
if (listingDataFromDb == null)
{
listingDataFromDb = new ListingData()
{
//use the new arrival's listing_id
listing_id = item.ListingData.listing_id
};
ctx.ListingData.Add(listingDataFromDb);
ctx.SaveChanges();
}
//add the Listing by using the listingDataFromDb, which now references the db ListingData
ctx.Listing.Add(new Listing()
{
id = counter++,
creation = item.creation,
ListingData = listingDataFromDb
});
ctx.SaveChanges();
}
}
I assume that besides the Data object reference you also have the primitive foreign key field listing_id in your Listing class. If not, I recommend adding it.
You could start by fetching the existing listing_ids in a list or array. That saves numerous database round trips later.
Then the process is really simple: for each Listing object that arrives check whether its listing_id occurs in the pre-fetched list:
If so, do nothing with ListingData - just add (or update) the Listing, including the listing_id property.
If not, add the Listing and set Listing.Data with the ListingData object, both as new (Added) objects. EF will set the keys.
(Note that this assumes that there are no concurrent users modifying ListingData, so it is safe to take a snapshot of the Id's)

Categories