ICollection<>.Contains in EF as HashSet fails - c#

I have an object defined as such:
public class QuestionSetAssignee
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<QuestionSet> QuestionSets { get; set; }
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return false;
}
QuestionSetAssignee qsa = obj as QuestionSetAssignee;
return Id == qsa.Id;
}
}
The following statement:
QuestionSetAssignees.Contains(director)
in
public bool isEditable()
{
ApplicationDbContext db = new ApplicationDbContext();
QuestionSetAssignee director = db.QuestionSetAssignees.Find((int)QuestionSetAssigneeEnum.Director);
if (Conference.AcceptingDirectorApplications && QuestionSetAssignees.Contains(director))
{
return false;
}
return true;
}
returns false, when as far as i can tell is should return true. (Note: Conference.AcceptingDirectorApplications returns true)
In case it's not immediately clear, the director object and the HashSet objects come through as DynamicProxies (due to EF and object hierarchy).
Here is the director object:
(Click for larger view)
and here is the QuestionSetAssignees object:
(Click for larger view)
I do not have control over the type of QuestionSetAsignees as it is supplied by EF 6 (it is declared as an ICollection in the model. This also means I am unable to provide a compare object (well, as far as I know). All I want to do is be able to compare two QuestionSetAsignee objects. I have also tried implementing IEquatable, but that did not work.

The problem is it is turning your Contains() in to a SQL call so no matter what you put in Equals and GetHashCode() it won't matter because the database you are connecting to does not use them for testing equality (This is why "This" == "this" will return true when working with entity framework on a database who's collation is not case sensitive).
The "quick and dirty" way to fix it is to realize the collection in memory and then do the .Contains
QuestionSetAssignees.AsEnumerable().Contains(director))
But that will not give you very good performance. You will likely need to approach this query a different way so the SQL behaves like you want it to.
I think the following may work, but please test it and let me know if it does not, I will remove it.
QuestionSetAssignees.Select(assignee => assignee.Id).Contains(director.Id)

Related

Equals is not implemented

I have the following class in C# 10:
public sealed record Country : IEquatable<Country>
{
public string Language { get; set; } = "xx";
public bool Equals(Country? other)
{
if (other is null)
{
return false;
}
return Language == other.Language;
}
public override int GetHashCode() => Language.GetHashCode();
}
Which when compiling will bring the following compile time error:
Interface member 'bool System.IEquatable<Country?>.Equals(Country?)' is not implemented
Which is... a very weird error message for the type in question. I tried varying the nullability of the Country parameter, and I tried generating the "missing" method, which will generate the following method for my IDE:
public bool Equals(Country? other) => throw new NotImplementedException();
And then, of course, the error switches to
Member with the same signature is already declared
Generating the Equals() method directly will just override the existing method.
What is going on here? Not all of my colleagues have the same error message for this class, so it might just be something that has nothing to do with the class. (I think I'm the only one on Windows, for example.) dotnet build works, so it might just be a problem with Rider 2021.3.2, but that's the IDE my colleagues use as well.
Its related to your record usage, records already implement this interface and IEquatable is not needed
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/records#equality-members
Quick test in Visual studio and its likely IDE issue.
Records implement equality automatically: that's one of the main advantages of using one.
We can see this in SharpLab. If we paste in:
public sealed record Country
{
public string Language { get; set; } = "xx";
}
and select "Results: C#", we can see that the generated code includes:
public override int GetHashCode()
{
return EqualityComparer<Type>.Default.GetHashCode(EqualityContract) * -1521134295 + EqualityComparer<string>.Default.GetHashCode(<Language>k__BackingField);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object obj)
{
return Equals(obj as Country);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public bool Equals(Country other)
{
return (object)this == other || ((object)other != null && EqualityContract == other.EqualityContract && EqualityComparer<string>.Default.Equals(<Language>k__BackingField, other.<Language>k__BackingField));
}
as well as definitions of the == and != operators.
See here.
If you do want to override equality in a record, then you do that as you have done, by specifying your own bool Equals(Counter? other) and int GetHashCode() methods. There's no need to specify that the record implements IEquatable<Country> however, because the compiler will automatically add this interface for records.
Note that it's good practice to put in a test for EqualityContract == other.EqualityContract. This is used to make sure that you're not comparing a record of type Country with one which is a subclass of Country:
public bool Equals(Country? other)
{
if (ReferenceEquals(this, other))
return true;
if (other is null || EqualityContract != other.EqualityContract)
return false;
return Language == other.Language;
}
public override int GetHashCode() => Language.GetHashCode();
See on SharpLab.

Checking if Object has null in every property

I have class with multiple properties;
public class Employee
{
public string TYPE { get; set; }
public int? SOURCE_ID { get; set; }
public string FIRST_NAME { get; set; }
public string LAST_NAME { get; set; }
public List<Department> departmentList { get; set; }
public List<Address> addressList { get; set; }
}
sometimes this object return me with value in any property say
Employee emp = new Employee();
emp.FIRST_NAME= 'abc';
remaining values are null. This is OK
But, How do I check when all values in properties of objects are null
like string.IsNullOrEmpty() for object ?
curretly I am checking like this;
if(emp.FIRST_NAME == null && emp.LAST_NAME == null && emp.TYPE == null && emp.departmentList == null ...)
EDIT
This answer has received some votes in the last time, so I decided to improve it a little, adding simple caching so that ArePropertiesNotNull does not retrieve the properties every time it is called, but rather only once for every type.
public static class PropertyCache<T>
{
private static readonly Lazy<IReadOnlyCollection<PropertyInfo>> publicPropertiesLazy
= new Lazy<IReadOnlyCollection<PropertyInfo>>(() => typeof(T).GetProperties());
public static IReadOnlyCollection<PropertyInfo> PublicProperties => PropertyCache<T>.publicPropertiesLazy.Value;
}
public static class Extensions
{
public static bool ArePropertiesNotNull<T>(this T obj)
{
return PropertyCache<T>.PublicProperties.All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
}
(Old answer below.)
You could use reflection as proposed by Joel Harkes, e.g. I put together this reusable, ready-to-use extension method
public static bool ArePropertiesNotNull<T>(this T obj)
{
return typeof(T).GetProperties().All(propertyInfo => propertyInfo.GetValue(obj) != null);
}
which can then be called like this
var employee = new Employee();
bool areAllPropertiesNotNull = employee.ArePropertiesNotNull();
And now you can check the areAllPropertiesNotNull flag which indicates whether all properties are not null. Returns true if all properties are not null, otherwise false.
Advantages of this approach
It doesn't matter whether or not the property type is nullable or not for the check.
Since above method is generic, you can use it for any type you want and don't have to write boilerplate code for every type you want to check.
It is more future-proof in case you change the class later. (noted by ispiro).
Disadvantages
Reflection can be quite slow, and in this case it is certainly slower than writing explicit code as you currently do. Using simple caching (as proposed by Reginald Blue will remove much of that overhead.
In my opinion, the slight performance overhead can be neglected since development time and repetition of code are reduced when using the ArePropertiesNotNull, but YMMV.
Either you do this by writing down the code to check every property manually (best option) or you use reflection (read more here)
Employee emp = new Employee();
var props = emp.GetType().GetProperties())
foreach(var prop in props)
{
if(prop.GetValue(foo, null) != null) return false;
}
return true;
example from here
Note that int cannot be null! and its default value will be 0. thus its better to check prop == default(int) than == null
option 3
Another option is to implement INotifyPropertyChanged.
On a change set a boolean field value isDirty to true and than you only need to check if this value is true to know if any property has been set (even if property was set with null.
Warning: this method every property can still be null but only checks if a setter was called (changing a value).

How do the `EqualOperator()` and `NotEqualOperator()` methods work in this `ValueObject` implementation (Microsoft Docs)?

In Domain Driven Design, we're introduced to the concept of a ValueObject, where objects don't carry an identity.
Microsoft have provided an implementation of their ValueObject in their Microservices series, where they override Equals() so that two ValueObject's with the same values are considered identical.
I've included their implementation below, but my question is relating to the EqualOperator() and NotEqualOperator() methods - how does this work? when are they called?
I'm familiar with operator overloads, but this seems to be an implementation I've not seen before, and I can't find any documentation around it.
Here is the implementation:
public abstract class ValueObject
{
protected static bool EqualOperator(ValueObject left, ValueObject right)
{
if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
{
return false;
}
return ReferenceEquals(left, null) || left.Equals(right);
}
protected static bool NotEqualOperator(ValueObject left,
ValueObject right)
{
return !(EqualOperator(left, right));
}
protected abstract IEnumerable<object> GetAtomicValues();
public override bool Equals(object obj)
{
if (obj == null || obj.GetType() != GetType())
{
return false;
}
ValueObject other = (ValueObject)obj;
IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
IEnumerator<object> otherValues =
other.GetAtomicValues().GetEnumerator();
while (thisValues.MoveNext() && otherValues.MoveNext())
{
if (ReferenceEquals(thisValues.Current, null) ^
ReferenceEquals(otherValues.Current, null))
{
return false;
}
if (thisValues.Current != null &&
!thisValues.Current.Equals(otherValues.Current))
{
return false;
}
}
return !thisValues.MoveNext() && !otherValues.MoveNext();
}
// Other utilility methods
}
Here's an example of their object in use:
public class Address : ValueObject
{
public String Street { get; private set; }
public String City { get; private set; }
public String State { get; private set; }
public String Country { get; private set; }
public String ZipCode { get; private set; }
private Address() { }
public Address(string street, string city, string state, string country,
string zipcode)
{
Street = street;
City = city;
State = state;
Country = country;
ZipCode = zipcode;
}
protected override IEnumerable<object> GetAtomicValues()
{
// Using a yield return statement to return
// each element one at a time
yield return Street;
yield return City;
yield return State;
yield return Country;
yield return ZipCode;
}
}
Actually, I find it astonishing that Microsoft implemented a value type using a class. Usually, structs are much better for this purpose, unless your value objects get very large. For most usages of value types such as coordinates or colors, this is not the case.
Leaving this discussion aside, what happens here is the following: If you implement a value object, you need to implement Equals and GetHashCode correctly, which includes consistently to each other. However, these two methods are actually not very difficult but verbose to implement: You need to cast the object and then check each of its properties. In case you are using classes, you have an additional boilerplate factor which is the fact that you typically want to speed up equality check using the reference equality check. That is, two objects need not be the same to be equal, but if they are the same, then they are also equal.
The class you depicted here is an attempt to support this consistency problem and boilerplate problem for value objects that are using classes by abstracting away quite a few commonalities. All you need to provide are the fields that make up the identity. In most cases, these are simply all fields. You iterate them using a co-method.
Now, for the actual question of when EqualOperator and NotEqualOperator are actually called, I would guess they are simply helper functions to make the implementation of operators more easy: You would provide an overloaded == operator that simply returns EqualOperator and != that simply returns NotEqualOperator. You might ask why the value type base class does not have these operators? Well, I guess this is because this would mean that the compiler would allow you to apply == and != to different types of value objects using the overloaded operator.

Equality of two objects in NUnit

I am currently trying to test that two C# objects are the same (not referencing the same object, but have the same values). Trying to use Assert.Equals gives me "Assert.Equals should not be used for Assertions". What should I use ?
Use Asset.AreEqual.
The Asset class is a child of the object class (like any class in C#) and when you call Asset.Equals you are actually calling the method object.Equals which is not what you want to do.
Programmers of NUnit probably put an exception in Asset.Equals to prevent people from making the mistake of using the wrong equality method.
for this, you should override Equals Method in Your Class
public class Student
{
public int Age { get; set; }
public double Grade { get; set; }
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is Student))
{
return false;
}
Student st = obj as Student;
return (st.Age == this.Age &&
st.Grade == this.Grade);
}
}
then you can write this Code in Your Test Class:
Assert.AreEqual(st1,st2);

Relate two lists with LINQ extensions

I have two lists of different objects, one from a third party API and one from my database - and I'm trying to link the two as a relationship. Ideally with a similar effect of how DBML's create relationships for tables with foreign keys (Customer.Orders).
From third party:
class ApiObject {
public string ID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
... 30 other properties ...
}
From my database:
class DbmlObject {
public int ID { get; set; }
public string ApiID { get; set; }
public string OtherString { get; set; }
}
They are related through ApiObject.ID == DbmlObject.ApiID
I do not want to merge these, nor join them into some anonymous object (and explicitly list 30+ properties) - but rather to make the DbmlObject a linked property of ApiObject. i.e.: addressable as:
apiObject.DbmlObjects.First().OtherString or ideally apiObject.DbmlObject.OtherString since it is a 1 to 1 relationship.
In controller:
List<ApiObject> apiObjects = _thirdParty.GetObjects();
DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();
// relate them here
foreach (var apiObject in apiObjects)
Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.
It sounds like a join:
var combined = from api in apiObjects
join dbml in dbmlObjects on api.ID equals dbml.ApiID
select new { api, dbml }
In order to get DbmlObject "in" the ApiObject, you will need to either inherit ApiObject and construct a new one of that class, which includes the Dbml property, or create a entirely new class to return. If you need static typing this is the best you can do - of course you could (mis)use dynamic to get what you want.
In this case, you are mentioning (in comments) that the ApiObject class is from a third party library that you can't change - in this case I would probably choose to create a new type which takes an instance of both objects in the constructor and exposes the properties you need - a decorator. Yes, it looks like a lot of code, but it is not complex, good tools will autogenerate it for you - and you get the class that you need for your code to be succinct.
In case you want to go further with returning an IEnumerable<dynamic>, you could build a "combining dynamic" object based on DynamicObject that then responds to all the properties of ApiObject and DbmlObject - or just adds DbmlObject as a property. I am not saying this is the right way to go, it depends on what you need it for - remember you are losing type safety. Here is a simple example:
void Main()
{
dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
Console.WriteLine(dyn.X);
Console.WriteLine(dyn.Y);
}
public class Foo
{
public int X {get;set;}
}
public class Bar
{
public int Y { get;set;}
}
public class CombiningDynamic : DynamicObject
{
private object [] innerObjects;
public CombiningDynamic(params object [] innerObjects)
{
this.innerObjects = innerObjects;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
foreach(var instance in innerObjects)
{
Type t = instance.GetType();
PropertyInfo prop = t.GetProperty(binder.Name);
if (prop != null && prop.CanRead)
{
result = prop.GetValue(instance, null);
return true;
}
}
result = null;
return false;
}
}
Remember, this is example code. If you really go this way, you would want to perhaps override some more of the methods (TrySetMember, ...), and you most definetely would want to cache the reflection results so you don't need to walk the types each time - reflection is (comparatively) slow.

Categories

Resources