JSON Lists not removing duplicates with Distinct command - asp.net

Currently I am querying a web service that returns a JSON string.
url = #"redacted url;
returnValue = new WebClient().DownloadString(url);
I am putting the return results into a list of items defined in a model class. I am then running a second JSON call searching a different field with that same search term.
url2 = #"redacted url2;
returnValue2 = new WebClient().DownloadString(url2);
I then create my lists and combine the lists using AddRange.
List<Order> shipments = JsonConvert.DeserializeObject<List<Order>>(returnValue);
List<Order> shipments2 = JsonConvert.DeserializeObject<List<Order>>(returnValue2);
shipments.AddRange(shipments2);
As a result there are some duplicates. To try and only return unique records I am using the command Distinct when sending to my MVC view from the controller.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct().ToList());
But for some reason it's still returning duplicates.
Any ideas on what I am doing wrong here?
Thanks in advance for any help!

I ended up correcting it using Shyju's comment above.
I changed the Distinct to the following.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct(new OrderComparer()).ToList());
Then built the following compare functions
// Custom comparer for the Order class
class OrderComparer : IEqualityComparer<Order>
{
// Orders are equal if their names and order numbers are equal.
public bool Equals(Order x, Order y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the order's properties are equal.
return x.sWorkOrderNumber == y.sWorkOrderNumber && x.sCustomerOrderName == y.sCustomerOrderName;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Order order)
{
//Check whether the object is null
if (Object.ReferenceEquals(order, null)) return 0;
//Get hash code for the sCustomerOrderName field if it is not null.
int hashOrderName = order.sCustomerOrderName == null ? 0 : order.sCustomerOrderName.GetHashCode();
//Get hash code for the sWorkOrderNumber field.
int hashOrderCode = order.sWorkOrderNumber.GetHashCode();
//Calculate the hash code for the order.
return hashOrderName ^ hashOrderCode;
}
}

Related

Intersection between two HashSets in Java 8

I have an object as following :
public Class MyObjDTO {
private Long id;
private Boolean checked;
//getter and setters
#Override
public final int hashCode() {
Long id = getId();
return (id == null ? super.hashCode() : id.hashCode());
}
#Override
public boolean equals(final Object obj) {
if (this == obj)
return true;
if (!(obj instanceof MyObjDTO))
return false;
Long id = getId();
Long objId = ((MyObjDTO) obj).getId();
if (id.equals(objId)) {
return true;
} else {
return false;
}
}
}
And I have two hash sets containing some instances from this object :
HashSet oldSet = new HashSet();
oldSet.add(new MyObjDTO(1,true));
oldSet.add(new MyObjDTO(2,true));
oldSet.add(new MyObjDTO(3,false));
HashSet newSet = new HashSet();
newSet.add(new MyObjDTO(1,false));
newSet.add(new MyObjDTO(2,true));
newSet.add(new MyObjDTO(4,true));
So what I want to do here is to select objects that are in the newSet and not in the oldSet, in this case its : new MyObjDTO(4,true) which I did using this :
Stream<MyObjDTO> toInsert = newSet.stream().filter(e -> !oldSet.contains(e));
Then I want to select objects that are in the oldSet and not in the newSet, in this case its :new MyObjDTO(3,false) which I did using this :
Stream<MyObjDTO> toRemove = oldSet.stream().filter(e -> !newSet.contains(e));
The last step is that I want to select the objects that are in both newSet and oldSet but they have a different value for the attribute checked , in this case it's : new MyObjDTO(1,false).
What I tried is this :
Stream<MyObjDTO> toUpdate = oldSet.stream().filter(newSet::contains);
But this one will return both new MyObjDTO(1,false) and new MyObjDTO(2,true).
How can I solve this ?
One way is to first use a map and then adjust your filter condition:
Map<MyObjDTO, Boolean> map = newSet.stream()
.collect(Collectors.toMap(Function.identity(), MyObjDTO::getChecked));
Stream<MyObjDTO> toUpdate = oldSet.stream()
.filter(old -> newSet.contains(old) && old.getChecked() != map.get(old));
Firstly, your equals() and hashCode() methods violate their basic contract. As per the javadoc of hashCode():
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
Your implementation of hashCode() does not follow this contract. Your first step should be to fix that.
Secondly, since Java 1.2 (nearly 20 years ago), java has provided the method removeAll() that does exactly what you want to do for the first part:
// Given these 2 sets:
HashSet<MyObjDTO> oldSet = new HashSet<>();
HashSet<MyObjDTO> newSet = new HashSet<>();
HashSet<MyObjDTO> onlyInNew = new HashSet<>(newSet);
onlyInNew.removeAll(oldSet);
// similar for onlyInOld
For the second part, you'll need to create a Map to find and get the object out:
Map<MyObjDTO, MyObjDTO> map = new HashMap<>O;
oldSet.forEach(o -> map.put(o, o);
HashSet<MyObjDTO> updated = new HashSet<>(newSet);
updated.removeIf(o -> oldSet.contains(o) && o.getChecked()() != map.get(o).getChecked());
In the last step, you rely on the equals() method of the DTO :
Stream<FonctionnaliteDTO> toUpdate = oldSet.stream().filter(newSet::contains);
The method uses only the id field to determinate object equality.
You don't want to do that.
You want to filter on a specific field : checked.
Besides, you should perform the operation on the result of the intersection of the two Sets.
Note that you should use simply Collection.retainAll() to compute the intersection between two collections:
Set<MyObjDTO> set = ...
Set<MyObjDTO> setTwo = ...
set.retainAll(setTwo);
Then you can filter objects that have both same id and checked value by using a double loop : for + iterator.
for (MyObjDTO dto : set){
for (Iterator<MyObjDTO> it = set.iterator(); it.hasNext();){
MyObjDTO otherDto = it.next();
if (otherDto.getId().equals(dto.getId()) &&
otherDto.getChecked() == dto.getChecked()){
it.remove();
}
}
}
You could do that with Stream but IHMO it could be less readable.

unable to evaluate viewState against Null

This method I am using to fill the data source for a grid view, but for when getnew is false, it won't return any value , just returns a list with a single null value in it.
private List<T> GetAll_T(bool getNew)
{
if (getNew)
return (ViewState["T"] = Get_T()) as List<T>;
//Get_T() returns a CustomList
return new List<T>
{
ViewState["T"] != null ?
ViewState["T"] as T:
(T)(ViewState["T"] = Get_T()) Collection
};
}
it gives me a warning for second line[when view state is null].expression is always false
why there is warning, when it's logically correct !
It is not clear from your code snippet what CustomerService.GetAllCustomer() returns.
You use it both like it returns a list on line(2) of the function and like it returns a single object on line(8).
I suggest writing it like this
private List<CustomerMaster> GetAllCustomer(bool getNew)
{
if (getNew || null == ViewState["CustomerDataset"])
ViewState["CustomerDataset"] = CustomerService.GetAllCustomer();
return ViewState["CustomerDataset"] as List<CustomerMaster>;
}

Searching for a string in a single column in a table within an ASP.NET MVC application

I have a table named Orders that has a column named OrderCode that stores a string that I randomly generate at the time of creation.
I want to make sure this string (OrderCode) is unique before I save it to my table.
How I have attempted to do this:
bool isUnique = false;
var order = new Order();
var code = RandomCode.Generate();
while (isUnique == false) // checks to see if the code we generated is unique among all generated codes, if not, will generate another code
{
var activeOrders = storeDB.Orders.Find("OrderCode", code);
if (activeOrders == null)
{
isUnique = true;
}
else
{
code = RandomCode.Generate();
}
}
order.OrderCode = code;
The problem appears to be that the DbSet<TEntity>.Find Method is actually used to search through primary keys - but I am needing to search for a string that is not a primary key.
What is a correct approach to this situation?
if (context.Orders.Any(o => o.OrderCode == code))
{
// key found
}
if (context.Orders.FirstOrDefault(o => o.OrderCode == code) != null)
{
// key found
}
May I ask why you don't just use a System.Guid though (Guid.NewGuid().ToString())? This would virtually eliminate this kind of issue.

Picking out Just JSON Data Returned from ASP.NET MVC3 controller Update

I've got data returned from my JavaScript client that just includes the data that has changed. That is, I may have an array with each row containing 10 columns of JSON downloaded, but on the Update, only the data that is returned to me is the data that got updated. On my update, I only want to update those columns that are changed (not all of them).
In other words, I have code like below but because I'm passing in an instance of the "President" class, I have no way of knowing what actually came in on the original JSON.
How can I just update what comes into my MVC3 update method and not all columns. That is, 8 of the columns may not come in and will be null in the "data" parameter passed in. I don't want to wipe out all my data because of that.
[HttpPost]
public JsonResult Update(President data)
{
bool success = false;
string message = "no record found";
if (data != null && data.Id > 0)
{
using (var db = new USPresidentsDb())
{
var rec = db.Presidents.FirstOrDefault(a => a.Id == data.Id);
rec.FirstName = data.FirstName;
db.SaveChanges();
success = true;
message = "Update method called successfully";
}
}
return Json(new
{
data,
success,
message
});
}
rec.FirstName = data.FirstName ?? rec.FirstName;
I would use reflection in this case because the code will be too messy like
if (data.FirstName != null)
rec.FirstName = data.FirstName
.
.
.
and so on for all the fields
Using reflection, it would be easier to do this. See this method
public static void CopyOnlyModifiedData<T>(T source, ref T destination)
{
foreach (var propertyInfo in source.GetType().GetProperties())
{
object value = propertyInfo.GetValue(source, null);
if (value!= null && !value.GetType().IsValueType)
{
destination.GetType().GetProperty(propertyInfo.Name, value.GetType()).SetValue(destination, value, null);
}
}
}
USAGE
CopyOnlyModifiedData<President>(data, ref rec);
Please mind that, this won't work for value type properties.

Flex looping through object

Im trying to extend the flex ArrayCollection to be able to search for an object containing specific data and give it back.
Here is my function:
public function getItemContaining(value: String): Object {
//Loop through the collection
for each(var i: Object in this) {
//Loop through fields
for(var j: String in i) {
//If field value is equal to input value
if(i[j] == value) {
return i;
}
}
}
//If not found
return null;
}
Problem is j is always null so the second loop never works. So I read flex loop descriptions and actually it should work just fine. What can possibly be the problem?
Try it like this:
for (var name:String in myObject){
trace(name + ":" + myObject[name];
}
Okay that was actually the same you were doing. The error must be in this line:
for each(var i: Object in this) {
Try using this:
for each(var i: Object in this.source) {
My first instinct would be to have a look at data type. You're setting up a loop declaring j:String and the symptom is that j is always null. This suggests to me that Flex is failing to interpret the elements of i as strings. If Flex only recognizes the elements of i as Objects (because all Strings are Objects, and Objects are the lowest common denominator), it would return null for j:String.
Try this for your inner loop:
for(var j: Object in i) {
//If field value is equal to input value
if(i[j] is String && (i[j] as String) == value) {
return i;
}
}
if you are using ArrayCollection as your datasource, you should look at using the IViewCursor interface. You can supply a custom compare function, or supply the fields top compare to. This interface is well documented with examples in adobe/livedocs
var _cursor:IViewCursor;
var _idSortField:SortField;
var _idSort:Sort = new Sort();
_idSortField = new SortField();
_idSortField.compareFunction = this.myCompareFunction;
_idSort.fields = [_idSortField];
myArrayCollection.sort = _idSort;
myArrayCollection.refresh();
_cursor = myArrayCollection.createCursor();
if (_cursor.findAny(search))
return _cursor;
if you are search for a value in a specific property, then its even easier. Here's the link to adobe livedocs on this topic

Resources