ASP.NET Core Web API Not Returning List of Child Items - asp.net-core

I am creating a ASP.NET Core web API that uses EF Core. I have a GET endpoint that returns a list of reports from the database. I have a related table which stores screenshots for the reports. The reportId is the foreign key in the images table.
I have a List item in the reports class which points to the ImagesList class.
I have the foreign key reportId in the ImageList class and identified as a foreign key. I also have a navigation property setup to the Reports class.
Reports Class:
[Table("Vw_ReportsList", Schema = "pbi")]
public class Reports
{
[Key]
public string reportId { get; set; }
[Required]
public string reportName { get; set; }
public string reportDescription { get; set; }
public string reportType { get; set; }
public string reportAuthor { get; set; }
public string reportLastUpdate { get; set; }
public string reportLastExecution { get; set; }
public List<ImagesList> Screenshots { get; set; }
//collection navigation property
}
ImageList Class:
[Table("Vw_ScreenshotsList", Schema = "pbi")]
public class ImagesList
{
[Key]
public int id { get; set; }
public string fileNameTest { get; set; }
public string imageData { get; set; }
public string created { get; set; }
public string reportId { get; set; }
[ForeignKey("reportId")]
public virtual Reports Reports { get; set; }
//navigation property
}
Context:
public class ServiceCatalogContext : DbContext
{
public ServiceCatalogContext(DbContextOptions<ServiceCatalogContext> options) : base(options) { }
public DbSet<Reports> Reports { get; set; }
public DbSet<ImagesList> ImagesLists { get; set; }
public DbSet<Images> Images { get; set; }
//used for the image upload POST call
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// modelBuilder.Entity<ImagesList>().HasOne<Reports>().WithMany().HasForeignKey(s => s.reportId);
modelBuilder.Entity<ImagesList>().HasOne(s => s.Reports).WithMany(s => s.Screenshots).HasForeignKey(s => s.reportId);
modelBuilder.Entity<Reports>().HasMany(r => r.Screenshots).WithOne().HasForeignKey(r => r.reportId);
}
}
My API works and returns the list of reports with no errors but I do not receive the screenshots list that I am expecting.
Here is a sample of the API output:
{
"reportId": "AC79F4CD-3771-42B2-B7F8-46AE4CE8DC80",
"reportName": "Dashboard Usage Metrics Report",
"reportDescription": "DESCRIPTION HERE - Dashboard Usage Metrics Report",
"reportType": "Excel",
"reportLastUpdate": "07/22/2020",
"reportLastExecution": "07/23/2020"
},
{
"reportId": "138CD5FA-6B5A-4C63-A449-DA9A9BBBF689",
"reportName": "Report Usage Metrics Report",
"reportDescription": "DESCRIPTION HERE - Report Usage Metrics Report",
"reportType": "Excel",
"reportLastUpdate": "07/22/2020",
"reportLastExecution": "07/23/2020"
}
I not receiving any error message from the API so I am not sure what I missed in order for each report to return the related images.
Edit: Adding Controller action
[HttpGet]
[EnableQuery()] //enabled OData querying
public IQueryable<Reports> Get()
{
return _context.Reports;
}
Edit: Updated ImagesList class
I also have Odata installed so here the metadata if that is of help:
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="ServiceCatalog.API.Entities" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Reports">
<Key>
<PropertyRef Name="reportId" />
</Key>
<Property Name="reportId" Type="Edm.String" Nullable="false" />
<Property Name="reportName" Type="Edm.String" Nullable="false" />
<Property Name="reportDescription" Type="Edm.String" />
<Property Name="reportType" Type="Edm.String" />
<Property Name="reportLastUpdate" Type="Edm.String" />
<Property Name="reportLastExecution" Type="Edm.String" />
<NavigationProperty Name="Screenshots" Type="Collection(ServiceCatalog.API.Entities.ImagesList)" />
</EntityType>
<EntityType Name="ImagesList">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.Int32" Nullable="false" />
<Property Name="fileNameTest" Type="Edm.String" />
<Property Name="imageData" Type="Edm.String" />
<Property Name="created" Type="Edm.String" />
<Property Name="reportId" Type="Edm.String" />
<NavigationProperty Name="Reports" Type="ServiceCatalog.API.Entities.Reports">
<ReferentialConstraint Property="reportId" ReferencedProperty="reportId" />
</NavigationProperty>
</EntityType>
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="Container">
<EntitySet Name="reports" EntityType="ServiceCatalog.API.Entities.Reports" />
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

Design your model like below:
[Table("Vw_ReportsList", Schema = "pbi")]
public class Reports
{
[Key]
public string reportId { get; set; }
[Required]
public string reportName { get; set; }
public string reportDescription { get; set; }
public string reportType { get; set; }
public string reportAuthor { get; set; }
public string reportLastUpdate { get; set; }
public string reportLastExecution { get; set; }
public List<ImagesList> Screenshots { get; set; }
//collection navigation property
}
[Table("Vw_ScreenshotsList", Schema = "pbi")]
public class ImagesList
{
[Key]
public int id { get; set; }
public string fileNameTest { get; set; }
public string imageData { get; set; }
public string created { get; set; }
public string reportId { get; set; }
// [ForeignKey("reportId")]
public virtual Reports Reports { get; set; }
//navigation property
}
And your DbContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ImagesList>().HasOne(s => s.Reports)
.WithMany(s => s.Screenshots).HasForeignKey(s => s.reportId);
//modelBuilder.Entity<Reports>().HasMany(r => r.Screenshots).WithOne().HasForeignKey(r => r.reportId);
}
Your controller:
[HttpGet]
public IQueryable<Reports> Get()
{
return _context.Reports.Include(r=>r.Screenshots);
}
Be sure to install Microsoft.AspNetCore.Mvc.NewtonsoftJson then use the following code:
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});

Related

How to pass generic list value to InOutArgument declared in Workflow Xaml

I have a entity class SEBLInBound as mentioned below
public class SEBLInbound
{
public int MEME_CK
{
get;
set;
}
public String EligibilityBeginDate
{
get;
set;
}
public String EligibilityEndDate
{
get;
set;
}
public Char VoidIndicator
{
get;
set;
}
public Char ReInstate
{
get;
set;
}
public char PriorToGoLive
{
get;
set;
}
}
I have declared a INOutArgument in XAML with type of this Entity class
<x:Members>
<x:Property Name="ErrorMsg" Type="OutArgument(x:String)" />
<x:Property Name="InboundProp" Type="InOutArgument(local:SEBLInbound)" />
<x:Property Name="argument1" Type="InArgument(x:String)" />
<x:Property Name="argument2" Type="InArgument(x:String)" />
</x:Members>
now from cs file i want to pass list value List to this Xaml for manipulation.
Please let me know, how to pass the value to workflow
THanks in advance
You pass objects into Workflow arguments using a dictionary object where the Keys are the name of the argument.
IDictionary<string, object> inParams = new Dictionary<string, object>
{
{"InboundProp", _yourDataObject01 },
{"argument1", _yourDataObject02 },
{"argument2", _yourDataObject03 },
};
_workflowApplication = new WorkflowApplication(new MyWorkFlow(), inParams)
_workflowApplication.Run();

Deserialize Xml with RestSharp

I'm having problems getting RestSharp to deserialize some XML
this is a sample of the xml
<data xmlns:xlink="http://www.w3.org/1999/xlink">
<parameters xmlns="">
<query-strings>
<query-string value="testValue"></query-string>
</query-strings>
<sources>
<source id="database"></source>
</sources>
</parameters>
<objects>
<object xmlns="" type="testType">
<source id="database"></source>
</object>
<object xmlns="" type="testType">
<source id="database2"></source>
</object>
<object xmlns="" type="testType">
<source id="database3"></source>
</object>
</objects>
</data>
Below is the Class that I'm trying to deserialize to
public class Data
{
public Parameter Parameters { get; set; }
}
public class Parameter
{
public string InverseLookup { get; set; }
public string TypeFilters { get; set; }
public List<QueryString> QueryStrings { get; set; }
public List<Source> Sources { get; set; }
public List<Item> objects { get; set; }
}
public class QueryString
{
public string value { get; set; }
}
public class Source
{
public string Id { get; set; }
}
public class Item
{
public string Type { get; set; }
public Source Source { get; set; }
}
The problem that I have is the objects element, I just can't seem to get this to deserialize. Does anyone have any idea what's going on?
The problem appears to have been between the Keyboard and Chair. (aka I'm an idiot.)
public class Data
{
public Parameter Parameters { get; set; }
}
Should have been
public class Data
{
public Parameter Parameters { get; set; }
Public List<Item> Objects {get; set; }
}

Insert in two related table at once with Nhibernate

I have two entities like
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public int DataId { get; set; }
}
public class Data
{
public int DataId { get; set; }
public string details { get; set; }
public int PersnId{ get; set; }
}
as you see both table are relate to each other. I want a solution to insert data in both table at once. I 1-insert person, 2-insert data and then update person and it works but I'm looking for way to eliminate Update.
My mapping for person table:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="TestNhibrinate" assembly="TestNhibrinate">
<class name="TestNhibrinate.Entites.Person" table="Person" lazy="false">
<id name="PersonId" column="PersonId" type="int" >
<generator class="identity" />
</id>
<property name="Name" column="Name" type="String" length="50" />
<many-to-one name="Adress" class="TestNhibrinate.Entites.Adress" column="AdressId"/>
</class>
</hibernate-mapping>
and same mapping for data.
You entities should look like this:
public class Person
{
public Person()
{
DataCollection = new List<Data>();
}
public int PersonId { get; set; }
public string Name { get; set; }
public int DataId { get; set; }
public IList<Data> DataCollection{get;set;}
public void AddData(Data item)
{
if(!DataCollection.Contains(item))
{
DataCollection.Add(item);
}
}
}
public class Data
{
public int DataId { get; set; }
public string details { get; set; }
public Person Person{ get; set; }
}
This way you create a one-to-many relation from Person to Data. If you save your person entity after you added some data, the data will also be persisted. This depends on your cascade options offcourse.
I'm not sure how to map this with XML mappings, since i always use Fluent or Auto mappings.

nhibernate mapping error

I have view width columns:
ID,
TREE_NODE_ID,
ATTRIB_ID,
INT_VALUE,
DATE_VALUE,
STRING_VALUE,
and table:
ID,
PARENT_ID,
TREE_ID,
public interface ITreeNode
{
long Id { get; set; }
ITreeNode Parent { get; set; }
// I want to get:
IDictionary<IAttribute, IAllTreeNodeValues> SpecTreeNodeValues { get; set; }
}
public interface IAllTreeNodeValues
{
long Id { get; set; }
ITreeNode TreeNode { get; set; }
IAttribute Attribute { get; set; }
long? IntValue { get; set; }
DateTime DateValue { get; set; }
string StringValue { get; set; }
}
fragment of mapping file:
<map name="SpecTreeNodeValues" lazy="true">
<key column="TREE_NODE_ID"/>
<index-many-to-many column="ATTRIB_ID" class="Attribute"/>
<many-to-many class="AllTreeNodeValues"/>
</map>
got an error: An association from the table SpecTreeNodeValues refers to an unmapped class: GeneralData.Entity.Atribute
You misspelled Attribute here:
<index-many-to-many column="ATTRIB_ID" class="Atribute"/>

NHibernate: Returning extra properties from stored procedure not in model

Is there a way when executing a stored procedure with NHibernate to return an extra field that is not in the original model?
What I'm doing is creating a sproc to return search results of a Resource. It returns all of the normal fields of my Resource class, but also an extra field called Rank. Is there a way to map that on to the current Resource class (or even create a class that inherits from Resource and just adds that one property)?
The execution of my sproc is:
<sql-query name="GetRelatedResources">
<return alias="item" class="ResourceRanked">
<return-property column="Rank" name="Rank" />
<return-property column="ResourceId" name="Id" />
<return-property column="Name" name="Name" />
<return-property column="Description" name="Description" />
<return-property column="Filename" name="Filename" />
<return-property column="Filetype" name="Filetype" />
<return-property column="IsPublic" name="IsPublic" />
<return-property column="IsFeatured" name="IsFeatured" />
<return-property column="VideoEmbedCode" name="VideoEmbedCode" />
<return-property column="VideoId" name="VideoId" />
<return-property column="VideoPlayerId" name="VideoPlayerId" />
<return-property column="VideoPlayerKey" name="VideoPlayerKey" />
<return-property column="VideoHeight" name="VideoHeight" />
<return-property column="VideoWidth" name="VideoWidth" />
<return-property column="IsDeleted" name="IsDeleted" />
<return-property column="CreatedOn" name="CreatedOn" />
<return-property column="ModifiedOn" name="ModifiedOn" />
<return-property column="CreatedBy" name="CreatedBy" />
<return-property column="ModifiedBy" name="ModifiedBy" />
<return-property column="CreatedByName" name="CreatedByName" />
<return-property column="ModifiedByName" name="ModifiedByName" />
</return>
exec dbo.gbi_sp_GetRelatedResources :pageSize, :pageIndex, :resourceId
</sql-query>
And my class:
public class Resource : DomainEntity
{
[Required(ErrorMessage = "Please enter a name"), StringLength(100, ErrorMessage = "Name length can not exceed 100 characters")]
public virtual string Name { get; set; }
[StringLength(200, ErrorMessage = "Description length can not exceed 200 characters")]
public virtual string Description { get; set; }
public virtual string Filename { get; set; }
public virtual string Filetype { get; set; }
public virtual bool IsPublic { get; set; }
public virtual bool IsFeatured { get; set; }
[StringLength(500, ErrorMessage = "Embed Code length can not exceed 500 characters")]
public virtual string VideoEmbedCode { get; set; }
public virtual long? VideoId { get; set; }
public virtual long? VideoPlayerId { get; set; }
[StringLength(100, ErrorMessage = "Player Key length can not exceed 100 characters")]
public virtual string VideoPlayerKey { get; set; }
public virtual int? VideoHeight { get; set; }
public virtual int? VideoWidth { get; set; }
//public virtual int Rank { get; set; }
public virtual string Format {
get
{
if (ResourceFileType == ResourceFileType.EmbeddedVideo || ResourceFileType == ResourceFileType.VideoPlayer)
return "Video";
switch (Filetype)
{
case "pdf":
return "Adobe Acrobat";
case "docx":
case "doc":
return "Microsoft Word";
case "ppt":
case "pptx":
return "Microsoft PowerPoint";
case "xls":
case "xlsx":
return "Microsoft Excel";
default:
return Filetype.ToUpper();
}
}
}
public virtual ResourceFileType ResourceFileType
{
get
{
if (VideoId.HasValue)
return ResourceFileType.VideoPlayer;
if (!VideoEmbedCode.IsNullOrEmpty() || VideoId.HasValue)
return ResourceFileType.EmbeddedVideo;
return ResourceFileType.Document;
}
}
public virtual IEnumerable<Market> Markets { get; set; }
public virtual IEnumerable<Workstream> Workstreams { get; set; }
public virtual IEnumerable<Tag> Tags { get; set; }
public virtual IEnumerable<Topic> Topics { get; set; }
public virtual IEnumerable<ResourceType> Types { get; set; }
public override string ToString()
{
return Id + " - " + Name;
}
}
Ideally I'd like to just make a class like this to extend Resource
public class ResourceRanked : Resource
{
public virtual int Rank { get; set; }
}
But I can't get that to work unless I duplicate the xml mapping of the Resource class. I've looked at subclasses for nhibernate, but they don't seem to fit what I'm trying to do.
I couldn't find any suitable solution that worked for me, so I unfortunately just had to map another class specifically for the return result of the stored proc.
The better way to do this is to create a view on the tables from which the joined resultset is required and query that view in the stored procedure and map that view in the .hbm file . You can check the detail at the link http://sachinpachori10.blogspot.in/2013/06/nhibernate-returning-extra-properties.html