Map navigation properties in Dapper.Net using stored procedure - c#

I am using Dapper.Net to get data from SQL Server database.
Here is my POCO classes
public partial class Production
{
public System.Guid ProductionId { get; set; }
public System.Guid SurveyId { get; set; }
public Nullable<int> PercentComplete { get; set; }
public string CompletedBy { get; set; }
public string DeliverTo { get; set; }
public virtual SurveyJob SurveyJob { get; set; }
}
public partial class SurveyJob
{
public SurveyJob()
{
this.Productions = new HashSet<Production>();
}
public System.Guid SurveyId { get; set; }
public string JobTitle { get; set; }
public Nullable<int> Status { get; set; }
public Nullable<int> JobNumber { get; set; }
public Nullable<System.DateTime> SurveyDate { get; set; }
public Nullable<System.DateTime> RequiredBy { get; set; }
public virtual ICollection<Production> Productions { get; set; }
}
I want to get all productions along with their SurveyJob information. Here is my SQL query in the stored procedure which returns these columns
SELECT
P.ProductionId, S.SurveyId,
P.PercentComplete, P.CompletedBy, P.DeliverTo,
S.JobTitle, S.JobNumber, S.RequiredBy, S.Status, S.SurveyDate
FROM
dbo.Production P WITH(NOLOCK)
INNER JOIN
dbo.SurveyJob S WITH(NOLOCK) ON S.SurveyId = P.SurveyId
Problem is that I am getting Production data but SurveyJob object is null.
Here is my c# code
var result = await Connection.QueryAsync<Production>("[dbo].[GetAllProductions]", p, commandType: CommandType.StoredProcedure);
I am getting SurveyJob object null as shown in image.
Need help. What I am doing wrong?

Your model is malformed for the query you executed, your query will return a plain object (dapper will always return plain objects), so you need a class with all the properties you're selecting.
Change your model to this:
public partial class ProductionSurvey
{
public System.Guid ProductionId { get; set; }
public System.Guid SurveyId { get; set; }
public Nullable<int> PercentComplete { get; set; }
public string CompletedBy { get; set; }
public string DeliverTo { get; set; }
public System.Guid SurveyId { get; set; }
public string JobTitle { get; set; }
public Nullable<int> Status { get; set; }
public Nullable<int> JobNumber { get; set; }
public Nullable<System.DateTime> SurveyDate { get; set; }
public Nullable<System.DateTime> RequiredBy { get; set; }
}

Related

Reference to application users always returning null even though included

My Club has many members so I have added the following virtual property Members my question is when I want to list the club members shouldn't adding just the virtual load this into lazy loading am using .net 5.0.1 at present.
var members = _context.Clubs.Include(c=>c.Members).Where(w => w.ClubId == tennantId ).ToList();
When I look at var members even when the members have been included it is zero even though the teannatId matches.
public class MSFSAddonDBContext : IdentityDbContext<ApplicationUser>
{
public MSFSAddonDBContext(DbContextOptions<MSFSAddonDBContext> options)
: base(options)
{
}
public DbSet<Club> Clubs { get; set; }
public virtual List<ApplicationUser>? Members { get; set; }
}
This is my controller method.
public void IActionResult ClubMembers()
{
var tennantId = GetTennantId().Result;
var members = _context.Clubs.Include(c=>c.Members).Where(w => w.ClubId == tennantId ).ToList();
return View(members);
}
There are two members references at top level and inside the clubs.
This is the club class
public class Club
{
public int Id { get; set; }
public Guid? TeannatId { get; set; }
public Guid? ClubId { get; set; }
public Guid? UserId { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public string? Url { get; set; }
public int? ClubLikes { get; set; }
public int? ClubDislikes { get; set; }
public int? MembersCount { get; set; }
public string? Logo { get; set; }
public List<Flight>? Flights { get; set; }
public string? ThumbNail { get; set; }
public DateTimeOffset? GpdrRemoveRequestDate { get; set; }
public bool? isGpdrRemoveRequest { get; set; }
public DateTimeOffset? BannedTime { get; set; }
public TimeSpan? BanPeriod { get; set; }
public bool? isBanned { get; set; }
public bool? isActive { get; set; }
public bool? isDeleted { get; set; }
public DateTime? CreatedDate { get; set; }
public string? CreatedBy { get; set; }
public virtual List<ApplicationUser>? Members { get; set; }
}
Edit 2
This is the application user class.
public class ApplicationUser : IdentityUser
{
public enum UserTypeEnum
{
Guest=0,
User=1,
Author=2,
AddonOwner=3,
GroupOwner=5,
ClubMember=6,
ClubAdmin=7,
SuperAdmin=199,
BandUser=999
}
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? GamerTag { get; set; }
public bool? isOnline { get; set; }
public int? UserType { get; set; }
public Guid? TennantId { get; set; }
public Guid? ClubId { get; set; }
public List<Badges>? Badges { get; set; }
}
NB As always with ef the primary keys in all my tables are the Id column thanks

C# MVC Model view connecting 2 different database columns

This is the first time I have attempted to join information from one database to the other. I have a accounting database and a regular site database. Trying to keep them separate. I have a page that shows Transactions but am getting the information for a few of the columns from the regular database by way of Id's. Below is my Model. I am showing nothing in the fields for the items in the other database.
public class Transaction
{
[Key]
public Guid TransactionId { get; set; }
public string Description { get; set; }
public int? CompanyId { get; set; }
public Guid? VendorId { get; set; }
public string InCheckNumber { get; set; }
public string OutCheckNumber { get; set; }
public string InvoiceNumber { get; set; }
public string PurchaseOrderNumber { get; set; }
public Guid LedgerAccountId { get; set; }
public decimal? DebitAmount { get; set; }
public decimal? CreditAmount { get; set; }
public DateTime TransactionDate { get; set; }
public string ModifiedBy { get; set; }
public DateTime? ModifiedDate { get; set; }
public string SavedDocument { get; set; }
public DateTime CreatedDate { get; set; }
public string CreatedBy { get; set; }
public bool IsCredit { get; set; }
public bool IsDebit { get; set; }
public Guid Type { get; set; }
[ForeignKey("LedgerAccountId")]
public LedgerAccount LedgerAccount { get; set; }
[ForeignKey("CompanyId")]
public CompanyNames Company { get; set; }
[ForeignKey("VendorId")]
public Vendors Vendor { get; set; }
}
I have added the 'using' of the General.Entities to this model. Is there something else i need to add for this?
Thanks in advance.
UPDATE:
See Question - Link to answer of question

How to gain access to table data through foreign key reference?

I have a statement in one of my entities which uses a foreign key to return an IEnumerable<CustomField>.
I have used LINQ in my repository to test the below method to see if it works and it does. But when I use the foreign key reference in the entity it returns null. Am I missing something here? How can I use a foreign key to gain access to the data in another entity.
Invoice entity:
[Table("vwinvoice")]
public class Invoice
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Sys_InvoiceID { get; set; }
[DisplayName("Inc.In Turnover")]
public bool Turnover { get; set; }
public int FK_StatusID { get; set; }
[DisplayName("Invoice No.")]
public string InvoiceNumber { get; set; }
[DisplayName("Invoice Date")]
public DateTime InvoiceDate { get; set; }
[DisplayName("Document Type")]
public string DocType { get; set; }
[DisplayName("Supplier Invoice No.")]
[Column("SupplierInvoiceNumber")]
public string SuppInvNumber { get; set; }
public int FK_SupplierID { get; set; }
[DisplayName("Account Number")]
public string AccountNumber { get; set; }
[DisplayName("Order Number")]
public string OrderNumber { get; set; }
[DisplayName("Order Date")]
public DateTime? OrderDate { get; set; }
[DisplayName("Currency Code_Doc")]
public string CurrencyCode_Doc { get; set; }
[DisplayName("Net Amount_Doc")]
public decimal? NetAmount_Doc { get; set; }
[DisplayName("VAT Amount_Doc")]
public decimal? VATAmount_Doc { get; set; }
[DisplayName("Gross Amount_Doc")]
[Required]
public decimal? GrossAmount_Doc { get; set; }
[DisplayName("Currency Code_Home")]
public string CurrencyCode_Home { get; set; }
[DisplayName("Net Amount_Home")]
public decimal? NetAmount_Home { get; set; }
[DisplayName("VAT Amount_Home")]
public decimal? VATAmount_Home { get; set; }
[DisplayName("Gross Amount_Home")]
public decimal? GrossAmount_Home { get; set; }
[DisplayName("Payment Reference")]
public string PaymentReference { get; set; }
[DisplayName("Supplier")]
public string AccountName { get; set; }
[DisplayName("Status")]
public string StatusName { get; set; }
[DisplayName("Auditor Comments")]
public string AuditorComments { get; set; }
[DisplayName("Reviewer Comments")]
public string ReviewerComments { get; set; }
[DisplayName("Data Source")]
[Required]
public string DataOrigin { get; set; }
public int DetailLineCount { get; set; }
public IEnumerable<CustomField> ClientData {
get {
//Use the CustomFields foreign key to gain access to the data returns null.
return GetCustomFieldData(this.CustomFields.Select(r => r));
}
}
private IEnumerable<CustomField> GetCustomFieldData(IEnumerable<Entities.CustomFields> enumerable) {
return (from f in enumerable
select new CustomField {
Name = f.FK_CustomHeader,
Value = f.Value
});
}
//Custom Field Additions
public virtual ICollection<CustomFields> CustomFields { get; set; }
}
CustomFields entity:
[Table("tblCustomFields")]
public class CustomFields
{
[Key]
public int ID { get; set; }
public int? FK_SysInvoiceID { get; set; }
[StringLength(255)]
public string FK_CustomHeader { get; set; }
[StringLength(255)]
public string Value { get; set; }
public virtual Invoice Invoices { get; set; }
public virtual CustomFieldHeaders CustomFieldHeaders { get; set; }
}
I also cannot place a breakpoint in the get statement to see what happens, why is this? It just skips over the breakpoint whenever I try to return a list of Invoices, which can be seen here:
public IQueryable<Invoice> Invoices
{
get
{
var x = _ctx.Invoices.ToList();
return _ctx.Invoices;
}
}
You are using the virtual keyword when declaring your CustomFields property. As such it will be lazy loaded. If you want the property to be populated once returned from the repository you will need to explicitly Include the table in your method:
var x = _ctx.Invoices.Include(i => i.CustomFields).ToList();
return _ctx.Invoices;
Or you can remove the virtual keyword and the property will always be populated, with the consequent performance hit of the database join and the extra data being returned whenever you access Invoices.

How to query IDBSet via linq

I have a table that i am attempting to query in order to create a menu. I am also querying the related tables to pair down result. I have a models project that contains all of my data models. In my Entities file I have
public IDbSet<Agent> Agents { get; set; }
public IDbSet<UsersLogin> UsersLogins { get; set; }
public IDbSet<Role> Roles { get; set; }
public IDbSet<UserRoleMapping> UserRoleMappings { get; set; }
public IDbSet<Qualifier> Qualifiers { get; set; }
public IDbSet<tblMenus> tblMenu { get; set; }
public IDbSet<tblUserMenuMapping> tblUserMenuMappings { get; set; }
public IDbSet<tblRoleMenuMapping> tblRoleMenuMappings { get; set; }
In my Interface i have ICollection<tblMenus> GetAllMenus();
Then i have my linq query which pares everything down and returns main menus and child menus.
public ICollection<tblMenus> GetAllMenus()
{
if (Global.CurrentProfile.UserID == 1)
{
return DataAccess.tblMenu.Where(m => !m.IsDeleted).ToList();
}
else
{
var UserInfo = GetUserInfo();
UserType = UserInfo.First().UserTypeID;
var childRoleMenus =
from menus in DataAccess.tblMenu
join roleMenus in DataAccess.tblRoleMenuMappings on menus.MenuID equals roleMenus.MenuID
join userRoles in DataAccess.UserRoleMappings on roleMenus.RoleID equals userRoles.RoleID
where userRoles.UserID == Global.CurrentProfile.UserID && !menus.IsDeleted
select menus;
var userChildMenus =
from menus in DataAccess.tblMenu
join userMenus in DataAccess.tblUserMenuMappings on menus.MenuID equals userMenus.MenuID
where userMenus.UserID == Global.CurrentProfile.UserID
select menus;
var childMenus = childRoleMenus.Union(userChildMenus).ToList();
However when i execute the query in my page it returns this error.
The specified type member 'MenuID' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported
Here are my models.
public class tblMenus : ModelBase
{
public int MenuID { get; set; }
public string MenuName { get; set; }
public string MenuLink { get; set; }
public Nullable<int> ParentID { get; set; }
public Nullable<bool> IsParent { get; set; }
public string IconImagePath { get; set; }
public Nullable<int> ApplicationID { get; set; }
public int CreatedBy { get; set; }
public System.DateTime CreatedOn { get; set; }
public string UpdatedBy { get; set; }
public Nullable<System.DateTime> UpdatedOn { get; set; }
public bool IsDeleted { get; set; }
public string ProcessedPage { get; set; }
public string MenuTarget { get; set; }
public Nullable<bool> IsEnabled { get; set; }
public string MenuCategory { get; set; }
public int MenuOrder { get; set; }
public virtual ICollection<tblRoleMenuMapping> tblRoleMenuMapping { get; set; }
public int RoleMenuID { get; set; }
public int RoleID { get; set; }
public int MenuID { get; set; }
public int CreatedBy { get; set; }
public System.DateTime CreatedOn { get; set; }
public Nullable<int> UpdatedBy { get; set; }
public Nullable<System.DateTime> UpdatedOn { get; set; }
public Nullable<bool> IsDeleted { get; set; }
public string ProcessedPage { get; set; }
public string PageAccessibility { get; set; }
public virtual ICollection<tblMenus> tblMenus { get; set; }
public virtual ICollection<Role> Role { get; set; }
public class tblUserMenuMapping : ModelBase
{
public int UserMenuID { get; set; }
public int UserID { get; set; }
public int MenuID { get; set; }
public Nullable<int> CreatedBy { get; set; }
public Nullable<System.DateTime> CreatedOn { get; set; }
public Nullable<int> UpdatedBy { get; set; }
public Nullable<System.DateTime> UpdatedOn { get; set; }
public bool IsDeleted { get; set; }
It's hard to say for sure without seeing the whole of both model classes and your database. Some things to check are:
Verify each respective 'MenuID' column exist in each underlying table. Because you aren't using mapping configurations, you need to make sure the column names follow the convention naming EF expects.
Verify their is a foreign key relationship between the two tables.
From a more general perspective, I would consider using configuration classes so your relationships are explicit and your model is more easily changed from the tables they map to.
Finally, you may see some clues by inspecting the SQL that EF has generated. Use the technique described in this post for any red flags (like EF is looking for a column that doesn't exist):
var result = from x in appEntities
where x.id = 32
select x;
var sql = ((System.Data.Objects.ObjectQuery)result).ToTraceString();

join two different list by id into one list

I've got two different list of two different objects. Then i got one list of a viewmodel that contains properties from both the objects and i want them to be joined into that list.
//Product
public string id { get; set; }
public string unitMeasurement { get; set; }
public Nullable<int> minOrderQty { get; set; }
public Nullable<int> packSize { get; set; }
public string leadTime { get; set; }
public Nullable<int> generalAccessoryCategoryId { get; set; }
public string Company { get; set; }
public Nullable<decimal> Weight { get; set; }
public Nullable<int> ProductType { get; set; }
//ProductDescription
public string id { get; set; }
public string language { get; set; }
public string shortDescription { get; set; }
public string detailDescription { get; set; }
public string Name { get; set; }
public Nullable<int> Rank { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public class ProductResponse
{
public string id { get; set; }
//Product
public string unitMeasurement { get; set; }
public Nullable<int> minOrderQty { get; set; }
public Nullable<int> packSize { get; set; }
public string leadTime { get; set; }
public Nullable<int> generalAccessoryCategoryId { get; set; }
public string Company { get; set; }
public Nullable<decimal> Weight { get; set; }
public Nullable<int> ProductType { get; set; }
//ProductDescription
public string language { get; set; }
public string shortDescription { get; set; }
public string detailDescription { get; set; }
public string Name { get; set; }
public Nullable<int> Rank { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
}
So i just want to join a list of products and a list of productdescriptions into a list of productResponse. How can i do this? id of product and productdescription is the same so thats what i want to join them on.
Join them on id and then call ToList:
var productResponses = from p in products
join pd in productDescriptions
on p.id equals pd.id
select new ProductResponse
{
id = p.id,
language = pd.language,
// ...
}
var list = productResponses.ToList();

Categories

Resources