I am making a call to a mongodb to get a list of values but one of the properties is coming back null, even though it has a value. I will try to give as much info as possible.
call to to get shipment info
var mobs = new List<ShipmentInformation>();
mobs = await GetAll();
Definition of GetAll() method:
public abstract class GenericDocumentRepository<TEntity> : IGenericDocumentRepository<TEntity>, IQueryable<TEntity>, IEnumerable<TEntity>, IEnumerable, IQueryable where TEntity : IEntity
{
public virtual Task<List<TEntity>> GetAll();
}
Shipmentinformation class:
public class ShipmentInformation : ResourceObject<string, ShipmentInformationAttributes, ShipmentInformationRelationships>
{
public override string type { get; set; }
public override ShipmentInformationAttributes attributes { get; set;
}
public override ShipmentInformationRelationships
relationships { get; set; }
}
public class ShipmentInformationRelationships : RelationshipsObject
{
public JobInfo Job { get; set; }
}
public class JobInfo
{
public List<JobData> data { get; set; }
}
Result:
}
here is image of data from mongo
As you can see job in mongo is not null but result says its null.
public class JobInfo
{
public List<JobData> Data { get; set; }
}
Should be named Data, so that the casing matches that of your Mongo Object.
However it would also be possible to add a BsonElement Attribute like this
public class JobInfo
{
[BsonElement("Data")]
public List<JobData> data { get; set; }
}
Related
I have the following structure of EF entities classes:
public abstract class CalendarItem
{
public Guid CalendarItemId { get; set; }
public Guid? ParentCalendarItemId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual CalendarItem ParentCalendarItem { get; set; }
public virtual ICollection<CalendarItem> ChildCalendarItems { get; set; }
}
public class CalendarSlot : CalendarItem
{
public bool IsAvailable { get; set; }
}
public class CalendarSession : CalendarEvent
{
public DateTimeOffset StartDateTime { get; set; }
public DateTimeOffset EndDateTime { get; set; }
}
Mapping is configured as follows:
public class CalendarItemMap
{
public static void Map(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CalendarItem>().ToTable("CalendarItem");
modelBuilder.Entity<CalendarItem>().HasKey(t => t.CalendarItemId);
modelBuilder.Entity<CalendarItem>().HasOne(ci => ci.ParentCalendarItem)
.WithMany(cs => cs.ChildCalendarItems).HasForeignKey(cs => cs.ParentCalendarItemId);
}
}
With DbSets as:
public DbSet<CalendarItem> CalendarItems { get; set; }
public DbSet<CalendarSession> CalendarSessions { get; set; }
public DbSet<CalendarSlot> CalendarSlots { get; set; }
My question is how to properly organize self-reference (tree) structure of the base class with inheritance provided. All types of entities, namely CalendarSlot and CalendarSession should have references to themselves, CalendarItem cannot be created as an instance.
In the database the tree structure is implemented in the CalendarItem table. CalendarSlot/CalendarSession tables have 1-1 relationship with CalendarItem.
The problem is that in my code I have a place with generic method which converts models to contracts for the API:
internal static TContract ToCalendarItem<TContract, TModel>(TModel calendarItemModel)
where TContract : Contract.CalendarItem, new()
where TModel : Model.CalendarItem
{
return new()
{
CalendarItemId = calendarItemModel.CalendarItemId,
Name = calendarItemModel.Name,
Description = calendarItemModel.Description,
ParentCalendarItem = calendarItemModel.ParentCalendarItem != null ? ToCalendarItem<TContract, TModel>(calendarItemModel.ParentCalendarItem) : null
};
}
and in the line
ParentCalendarItem = calendarItemModel.ParentCalendarItem != null ? ToCalendarItem<TContract, TModel>(calendarItemModel.ParentCalendarItem) : null
I have an error "Argument 1: Cannot convert from 'Model.CalendarItem' to TModel".
How can I tell the system that calendarItemModel.ParentCalendarItem should always be TModel (a class derived from Model.CalendarItem)?
What I am doing wrong here?
Thank you in advance.
I have a QueryFilter<TSearchFilter> class (see below). And I created a QueryFilter class that inherits from this class. I'm currently using the QueryFilter without specifying the type, like this:
var queryFilter = new QueryFilter();
To do this, I created a fake EmptySearchFilter class for achieving this. This works perfectly; no problem.
public class QueryFilter<TSearchFilter> where TSearchFilter : class
{
public QueryFilter()
{
SearchFilter = (TSearchFilter)Activator.CreateInstance(typeof(TSearchFilter));
}
public string SortBy { get; set; }
public int PageFirstIndex { get; set; }
public byte PageSize { get; set; }
public TSearchFilter SearchFilter { get; set; }
}
public class QueryFilter : QueryFilter<EmptySearchFilter> { }
public class EmptySearchFilter { }
But, I think that there's probably a way to avoid using this fake class (EmptySearchFilter) by doing something like:
public class QueryFilter : QueryFilter<typeof(Class)>{ }
Is there a way to do this?
You can reverse the inheritance chain like this:
public class QueryFilter
{
public string SortBy { get; set; }
public int PageFirstIndex { get; set; }
public byte PageSize { get; set; }
}
public class QueryFilter<TSearchFilter> : QueryFilter
where TSearchFilter : class, new()
{
public QueryFilter()
{
SearchFilter = new TSearchFilter();
}
public TSearchFilter SearchFilter { get; set; }
}
This way, the QueryFilter does not need to use a fake class.
Also, I've added a new() constraint to get rid of the Activator.CreateInstance call.
Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.
I'm currently on design stage in writing C# .NET Core application. I'm gonna use the generics to inherit some properties among all derived classes. The goal is to archive many 2 many relation of entities able to be tagged. The app concept is funky, because tag will contain related logic as constraint entity. I have problems with the proper where statements in generic class, to be able to use inherited Tags property for all Taggable Entities.
Here is abstraction:
public interface ITaggable
{
long TagId { get; set; }
Tag Tag { get; set; }
}
public interface IEntityTag<T> : ITaggable where T : Entity
{
long EntityId { get; set; }
T Entity { get; set; }
}
public abstract class TaggableEntity<T> : Entity where T : ITaggable
{
public ICollection<T> EntityTags { get; set; }
public List<Tag> Tags { get { return EntityTags.Select(x => x.Tag).ToList(); } }
}
public abstract class ConstraintBase<TSubject, TOwner>
: ConstraintEntity where TOwner : TaggableEntity<IEntityTag<TOwner>>
{
protected ConstraintBase(ConstraintId id, string description)
{
Id = id.Value();
Name = id.ToString();
Description = description;
IsExecutable = false;
}
public IEnumerable<TSubject> Validate(IEnumerable<TSubject> items, TOwner owner)
{
return items.Where(x => Validate(x, owner));
}
public void Execute()
{
if (IsExecutable) { OnExecuting(); }
}
protected abstract bool Validate(TSubject item, TOwner owner);
public abstract void OnExecuting();
}
And here concrete classes.
public class ConstraintEntity : Entity
{
public string Name { get; set; }
public string Description { get; set; }
public bool IsExecutable { get; set; }
public ConstraintId ConstraintId => (ConstraintId)Id;
}
public class EndWorkConstraint : ConstraintBase<Activity, User>
{
public EndWorkConstraint() : base(ConstraintId.EndWorkConstraint, "Check if user is allowed to end work")
{
}
protected override bool Validate(Activity item, User owner)
{
return item.ActivityId != ActivityId.EndWork;
}
public override void OnExecuting()
{
throw new System.NotImplementedException();
}
}
public class User : TaggableEntity<UserTag>
{
public string Login { get; set; }
public string Password { get; set; }
}
The question is: am I able to modify ConstraintBase where statement, to make EndWorkConstraint class do not raising an error, and still have the tags explicit avalible?
This is my first post on the forum, and I m really forced to use Yours wisdom. I'd be glad for any tips. Thanks in advance.
I am trying to write a Generic Base Service Class where after receiving the fist generic list of data as the actual type of Db Model Entity need a conversion to a new Generic View Model type of data.
I have tried list.ConvertAll() but always getting a build error for ConvertAll() method.
I also tried list.Cast<TVm>().ToList() this solve the build error but getting the run time error.
Here are my code snips of all classes and interfaces. Any help or suggestion is appreciated.
Entity Class
public abstract class Entity
{
[Key]
[Index("IX_Id", 1, IsUnique = true)]
public string Id { get; set; }
[DataType(DataType.DateTime)]
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
[DataType(DataType.DateTime)]
public DateTime Modified { get; set; }
public string ModifiedBy { get; set; }
[DefaultValue(true)]
public bool Active { get; set; }
}
BaseViewModel Class
public abstract class BaseViewModel<T> where T: Entity
{
protected BaseViewModel() { }
protected BaseViewModel(T model)
{
Id = model.Id;
Created = model.Created;
CreatedBy = model.CreatedBy;
Modified = model.Modified;
ModifiedBy = model.ModifiedBy;
Active = model.Active;
}
public string Id { get; set; }
public DateTime Created { get; set; }
public string CreatedBy { get; set; }
public DateTime Modified { get; set; }
public string ModifiedBy { get; set; }
public bool Active { get; set; }
}
IBaseService interface
public interface IBaseService<T, TVm> where T : Entity where TVm : BaseViewModel<T>
{
List<TVm> GetAll();
}
BaseService Class
public abstract class BaseService<TEntity, TVm> : IBaseService<TEntity, TVm> where TEntity: Entity where TVm : BaseViewModel<TEntity>
{
protected IBaseRepository<TEntity> Repository;
protected BaseService(IBaseRepository<TEntity> repository)
{
Repository = repository;
}
public virtual List<TVm> GetAll()
{
List<TVm> entities;
try
{
List<TEntity> list = Repository.GetAll().ToList();
entities = list.Cast<TVm>().ToList(); //runtime error
entities = list.ConvertAll(x => new TVm(x)); //build error
entities = list.ConvertAll(new Converter<TEntity, TVm>(TEntity)); //build error
}
catch (Exception exception)
{
throw new Exception(exception.Message);
}
return entities;
}
}
To create an instance of a generic type, you need the new()-constraint on it. However, that does not allow you to pass any parameters to it. You could try either
Using Activator to create an instance, like this
entities = list.ConvertAll(x => (TVm)Activator.CreateInstance(typeof(TVm), x));
or
Add the new()-constraint to TVm in the BaseService class signature, and add a method on the classes you pass to it as TVm that basically does what the current constructor does, but in a method, and call that after creating the new object.
I think the best option you tried is entities = list.ConvertAll(x => new TVm(x));. The reason it fails compilation is that, in C# inherited classes doesn't necessarily need to have same constructor as base class. Instead you should initialize TVm inside BaseService. Additionally, your try catch block does nothing more than losing some data and affecting StackTrace, so you better remove it. Below code should work for you.
public abstract class BaseService<TEntity, TVm>
: IBaseService<TEntity, TVm>
where TEntity: Entity
where TVm : BaseViewModel<TEntity>, new()
{
protected IBaseRepository<TEntity> Repository;
protected BaseService(IBaseRepository<TEntity> repository)
{
Repository = repository;
}
private TVm ConvertToViewModel(TEntity model)
{
return new TVm
{
Id = model.Id,
Created = model.Created,
CreatedBy = model.CreatedBy,
Modified = model.Modified,
ModifiedBy = model.ModifiedBy,
Active = model.Active,
};
}
public virtual List<TVm> GetAll()
{
List<TEntity> list = Repository.GetAll().ToList();
List<TVm> entities = list.ConvertAll(x => ConvertToViewModel(x));
return entities;
}
}