I am getting a rather weird casting error. Here is the code:
public class OrganizationLocation : IOrganizationLocation
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public interface IOrganizationLocation
{
string Name { get; }
}
public class Organization : IOrganization
{
public Guid Id { get; set; }
public string Alias { get; set; }
public virtual ICollection<OrganizationLocation> Location { get; set; }
public ICollection<IOrganizationLocation> Locations
{
get
{
return (ICollection<IOrganizationLocation>) Location;
}
}
}
public interface IOrganization
{
string Alias { get; }
ICollection<IOrganizationLocation> Locations { get; }
}
now when I try to run this via a service (backend data layer is EF6), the "Location" variable has all the values, however, the "Locations" variable fails to cast. If I try to do a safe cast, it comes back as null every time.
I'm not understanding why would the cast fail? It has same fields, both are ICollection Type, so why do I get a HashSet?
The reason why I am doing it this way is because for EF6 framework to be able to treat this class as a table it needs to have a concrete type and a public get/set. However, I do not wish to expose that, so I use interface instead and then inject the class when the interface is called. This way I only expose get method and on top of it I only expose interface layers.
Unable to cast object of type 'System.Collections.Generic.HashSet`1[Namespace.OrganizationLocation]' to type 'System.Collections.Generic.ICollection`1[Namespace2.IOrganizationLocation]'.
I was able to resolve this by changing the code to the following:
public class OrganizationLocation : IOrganizationLocation
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public interface IOrganizationLocation
{
string Name { get; }
}
public class Organization : IOrganization
{
public Guid Id { get; set; }
public string Alias { get; set; }
public virtual ICollection<OrganizationLocation> Location { get; set; }
public IEnumerable<IOrganizationLocation> Locations => Location
}
public interface IOrganization
{
string Alias { get; }
IEnumerable<IOrganizationLocation> Locations { get; }
}
Related
On one hand I have a list of capabilities, for example:
public interface ICapability
{
public string Name { get; }
}
public class RangeCapability<T> : ICapability
{
public string Name { get; set; }
public T Min { get; set; }
public T Max { get; set; }
}
public class SetCapability<T>
{
public string Name { get; set; }
public HashSet<T> Set { get; set; }
}
On the other hand I have a list of requirements
public interface IRequirement
{
public string Name { get; }
}
public class Requirement<T> : IRequirement
{
public string Name { get; set; }
public T Value { get; set; }
}
Both capability list may contain capabilities of different types T and requirement list may contain requirements of different types. The important thing is that if for a given name the underlying types match I should check if value is between min and max (for range class) or in a set like in the example below:
public class Entity
{
List<ICapability> Capabilities { get; set; }
public bool IsSatisfying(List<IRequirement> requirements)
{
foreach(var requirement in requirements)
{
var capability = Capabilities.FirstOrDefault(x => x.Name == requirement .Name);
//how to check if here if types match and if req. within range or in collection?
}
}
}
I am not sure how to match generic types of two different classes and then do the check suitable for the apropriate implementation (is within range/is present in set). Can somebody point me in the right direction how could I make it work?
I believe this is what you're looking for. Make the interfaces generic and also make the Entity class generic.
public interface INamed<T>
{
string Name { get; }
}
public interface ICapability<T> : INamed<T>
{
}
public class RangeCapability<T> : ICapability<T>
{
public string Name { get; set; }
public T Min { get; set; }
public T Max { get; set; }
}
public class SetCapability<T>
{
public string Name { get; set; }
public HashSet<T> Set { get; set; }
}
public interface IRequirement<T> : INamed<T>
{
}
public class Requirement<T> : IRequirement<T>
{
public string Name { get; set; }
public T Value { get; set; }
}
public class Entity<T>
{
List<ICapability<T>> Capabilities { get; set; }
public bool IsSatisfying(List<IRequirement<T>> requirements)
{
foreach (var requirement in requirements)
{
var capability = Capabilities.FirstOrDefault(x => x.Name == requirement.Name);
//how to check if here if types match and if req. within range or in collection?
if(capability is INamed<T>)
{
Console.WriteLine("types match");
}
}
}
}
I've created three interfaces - IUser, ICostCenter, IDepartment. IUser and IDepartment are properties of ICostCenter.
public interface ICostCenter
{
IDepartment Department { get; set; }
User.IUser CostCenterHead { get; set; }
}
The class implementing ICostCenter will be used in the DbContext for my db.
public class tblCostCenter : WorkingInterface.Interface.Organization.ICostCenter
{
public tblCostCenter()
{
this.ID = Guid.NewGuid().ToString();
}
public string ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
private WorkingInterface.Interface.User.IUser CostCenterHead { get; set; }
public string UserID { get; set; }
[ForeignKey("UserID")]
public Model.tblUser UserObject
{
get { return (Model.tblUser)this.CostCenterHead; }
set { this.CostCenterHead = value; }
}
private WorkingInterface.Interface.Organization.IDepartment Department { get; set; }
public string DepartmenID { get; set; }
[ForeignKey("DepartmenID")]
public Model.tblDepartment DepartmentObject
{
get { return (Model.tblDepartment)this.Department; }
set { this.Department = (Model.tblDepartment)value; }
}
}
I'm getting an error because I made the IUser and IDepartment properties private. How can I properly implement the interface? I want these properties to be hidden.
The interface is declared explicitly as public, that means that all the members declared in that interface MUST be public
So you need to declare both of these properties as public:
public WorkingInterface.Interface.User.IUser CostCenterHead { get; set; }
public WorkingInterface.Interface.Organization.IDepartment Department { get; set; }
NOTE: these have been declared as implicit implementations, so they are available to all contexts. If you want to hide them from general use, you can use explicit implementation.
Because you tried to use private accessibility, I assume you generally want to hide these properties from view, you can do this and still honor the interface contract by using explicit implementation syntax:
WorkingInterface.Interface.User.IUser ICostCenter.CostCenterHead { get; set; }
WorkingInterface.Interface.Organization.IDepartment ICostCenter.Department { get; set; }
They are still public but can only be accessed by first casting the object to the specific interface type explicitly.
tblCostCenter obj = new tblCostCenter();
...
// this wont work:
Console.WriteLine(obj.CostCenterHead);
// instead you will have to cast the object first
Console.WriteLine((obj as ICostCenter)).CostCenterHead);
// or if the local variable was an ICostCenter
ICostCenter costObj = obj;
Console.WriteLine(costObj.CostCenterHead);
...
// Pattern matching can also be helpful in these scenarios
if (obj is ICostCenter cc)
Console.WriteLine(cc.CostCenterHead);
If you want to use explicit declaration in your class you could try this:
WorkingInterface.Interface.User.IUser ICostCenter.CostCenterHead { get; set; }
public string UserID { get; set; }
[ForeignKey("UserID")]
public Model.tblUser UserObject
{
get { return ((ICostCenter)this).CostCenterHead as Model.tblUser; }
set { ((ICostCenter)this).CostCenterHead = value; }
}
WorkingInterface.Interface.Organization.IDepartment ICostCenter.Department { get; set; }
public string DepartmenID { get; set; }
[ForeignKey("DepartmenID")]
public Model.tblDepartment DepartmentObject
{
get { return ((ICostCenter)this).Department as Model.tblDepartment; }
set { ((ICostCenter)this).Department = value; }
}
this only works if:
Model.tblDepartment : IDepartment
Model.tblUser : User.IUser
New ASP.NET core (to the whole web thing actually). So, making controllers and also started implementing Interfaces for scalability (my code base is pretty big, and already feeling the heat implementing Interfaces too late down the line). I have a couple of classes like this -
public interface IParent {
string IParent1 { get; set; }
string IParent2 { get; set; }
string IParent3 { get; set; }
}
public class ChildClass1: IParent {
public string IParent1 { get; set; }
public string IParent2 { get; set; }
public string IParent3 { get; set; }
string ChildClass11 { get; set; }
string ChildClass12 { get; set; }
string ChildClass13 { get; set; }
}
public class ChildClass2 : IParent {
public string IParent1 { get; set; }
public string IParent2 { get; set; }
public string IParent3 { get; set; }
string ChildClass21 { get; set; }
string ChildClass22 { get; set; }
string ChildClass23 { get; set; }
}
I need to send an object which is of type ChildClass1 or ChildClass2 from my Angular/Typescript website (the json model is either ChildClass1 or ChildClass2), and one of my controllers will receive this -
[HttpPost, DisableRequestSizeLimit]
public async Task<IActionResult> Post(IParent parent)
{
if (parent is ChildClass1)
{
// Do something
}
if (parent is ChildClass2)
{
// Do something else
}
// Rest of the controller
...
}
Now the issue is, the arg parent of the controller is only receiving whatever properties it has. I.e. properties of childclasss are not deserialized and doesn't even exist (because the parent doesn't have them I think).
Can someone kindly suggest how to solve this, please? I would like the parent arg to hold full ChildClass1 or ChildClass2 variables and then typecast and perform their related operation.
Apologies if somethings doesn't make sense. Please let me know if you need more information. Many thanks in advance!
In the below example, I'm just trying to get Test_Person_Name.FirstName to map to something (anything) in TestPersonFlattened. At this point, considering the amount of time I've sunk into this, I'm not too hung up on what the destination property name is..I just want it to work.
public class Test_Person
{
public Test_Person_Name Test_Person_PublicName { get; set; }
}
public class Test_Person_Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class TestPersonFlattened
{
public string Test_Person_PublicNameFirstName { get; set; } // What do I call this property?
}
AutoMapper.Mapper.CreateMap<Test_Person, TestPersonFlattened>();
AutoMapper.Mapper.AssertConfigurationIsValid();
It seems like Test_Person_PublicNameFirstName should work, but I get an exception on AssertConfigurationIsValid(). I've also tried TestPersonPublicNameFirstName, Test_Person_PublicName_FirstName as destination property names.
It'd be unfavorable to rename the source property name, just because the source library is used in many other projects. Also, a ForMember() call isn't ideal, but I'll do it if there's no other option.
One way to do it would be to simply leave out "Test_Person_" from the PublicNameFirstName property of your TestPersonFlattened class, and use RecognizePrefixes() to make it so that AutoMapper ignores "Test_Person_" when attempting to map property names.
The following code succeeds:
public partial class App : Application
{
public App()
{
Mapper.Initialize(cfg =>
{
cfg.RecognizePrefixes("Test_Person_");
cfg.CreateMap<Test_Person, TestPersonFlattened>();
});
Mapper.CreateMap<Test_Person, TestPersonFlattened>();
Mapper.AssertConfigurationIsValid();
}
}
public class Test_Person
{
public Test_Person_Name Test_Person_PublicName { get; set; }
}
public class Test_Person_Name
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class TestPersonFlattened
{
public string PublicNameFirstName { get; set; } // This is what I call this property!
}
I have a class Employee:
public partial class Employee
{
public Employee()
{
this.Employees1 = new HashSet<Employee>();
}
public int Id { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public Nullable<int> ReportsToId { get; set; }
public virtual ICollection<Employee> Employees1 { get; set; }
public virtual Employee ReportsTo { get; set; }
}
And a view model for this:
public class EmployeeEditModel : MappedViewModel<Employee>
{
public int Id { get; set; }
public string Surname { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
public int? ReportsTo { get; set; }
}
MappedViewModel<T> declares a method:
public class MappedViewModel<TEntity>: ViewModel
{
public virtual TEntity MapToEntity()
{
return (TEntity)Mapper.Map(this, GetType(), typeof(TEntity));
}
}
When I call MapToEntity in an action method, as such
I get an exception from AutoMapper with the message:
Missing type map configuration or unsupported mapping.
Mapping types: Int32 -> Employee System.Int32 -> Leave.Data.Employee
Destination path: Employee.ReportsTo.ReportsTo
Source value: 5
My mappings are defined as follows:
public static void RegisterMaps()
{
Mapper.CreateMap<Employee, EmployeeCreateModel>();
Mapper.CreateMap<EmployeeCreateModel, Employee>();
}
The double reference Employee.ReportsTo.ReportsTo screams out to me that this exception is somehow caused by some sort of cyclical mapping quirk, but I what can I do about this? At very least I would like omit ReportsTo from the mapping and simply do this manually after calling MapToEntity. How can I even to this, and rather, what should I do for this pattern of AutoMapper problem?
You need to do more than simple Mapper.CreateMap as it won't magically figured out how to convert between EmployeeViewModel.ReportsTo (int?) and Employee.ReportsTo (Employee).
Either create a mapping between int and Employee or use the ForMember method to tell AutoMapper how to convert the ReportsTo property.