ASPNET Eager Loading doesn't work for HashSet - asp.net-core

I'm working on a project which has Database-First approach.
In the said project, I have Offer.OfferPlaces and OfferPlaces.Offer relation.
The first one doesn't seem to work, loading it via Include(x => x.OfferPlaces) yields empty collection, while loading Include(x => x.Offer) works fine and loads related Offer.
Is that a common issue in EFCore, do I have to implement a workaround of sorts or perhaps add something to OnModelCreating of the DbContext?
Here's the Offer model:
using Microsoft.EntityFrameworkCore.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace MarketplaceOffe.DAL.Model
{
[Table("Offers")]
public partial class Offer
{
public Offer()
{
OfferPlaces = new HashSet<OfferPlace>();
}
public long Id { get; set; }
public long CompanyId { get; set; }
public virtual ICollection<OfferPlace> OfferPlaces { get; set; }
}
}
And the OfferPlace model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
namespace MarketplaceOffe.DAL.Model
{
[Table("OfferPlaces")]
public partial class OfferPlace
{
public long Id { get; set; }
public long OfferId { get; set; }
public virtual Offer Offer { get; set; }
}
}

Related

How to create and record Multi Data in .net core?

I want to save new data to the table in the .net core structure. This table will be PerfomansID and CategoryID fixed, others incrementing by 1, and it will save these values up to 25 or 100 in the table.
For example, I will say PerformanceID=45, CategoryID=3, create up to 25 and it will record the SQL.
What kind of structure should I set up?
controller:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace KBT.Controllers
{
public class SalesSeatsController : Controller
{
private readonly ISalesSeatsRepository _salesSeatsRepository;
public SalesSeatsController(ISalesSeatsRepository SalesSeatsRepository)
{
_salesSeatsRepository = SalesSeatsRepository;
}
public IActionResult Index()
{
object Values = _viFinalSalesSeatsRepository.GetListAll();
return View(Values);
}
Table class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EntityLayer.Concrete
{
public class SalesSeats
{
public int? PerformanceID { get; set; }
public int? SeatsNumber { get; set; }
public int? SeatsSalesNumber { get; set; }
public int? DoorID { get; set; }
public int? SalesCategoriesID { get; set; }
public int? SeatsRate { get; set; }
}
}
I used to open manual records in excel and save them to SQL. I want to do this from the panel in .net core. I need to set up a for each loop here, but I couldn't succeed.
[table][1]

How to access a model to home view index.cshtml file in ASP.NET Core 5 MVC?

I am completely new to ASP.NET Core and following along the Microsoft's documentation and developing a simple web application. Sorry, if the question is not clear.
I have created a model, view and controller called Broadcast. This model has a field called live. I would like to access this model to home view's index.cshtml file which is a separate view.
I have tried including Broadcast view on the top at index.cshtml file home view
#model IEnumerable<SideCar.Models.Broadcast>
When I am accessing the model using #foreach I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Could you please guide, what should I learn to access the model into a different view? Thank you.
Here is the controller:
using Microsoft.AspNetCore.Mvc;
using SideCar.Data;
using SideCar.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SideCar.Controllers
{
public class BroadcastController : Controller
{
private readonly ApplicationDbContext _db;
public BroadcastController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Broadcast> objList = _db.Boradcast;
return View(objList);
}
}
}
and model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace SideCar.Models
{
public class Broadcast
{
[Key]
public int Id { get; set; }
public string BroadcastHeading { get; set; }
public string BroadcastDesc1 { get; set; }
public string BroadcastDesc2 { get; set; }
public DateTime ActiveDate { get; set; }
public DateTime ExpiryDate { get; set; }
public string Live { get; set; }
}
}
Change you index action to this:
public IActionResult Index()
{
var objList = _db.Set<Broadcast>().ToArray();
return View(objList);
}
Here are two solutions:
add #if (Model != null){} outside #foreach in view
use
IEnumerable<Broadcast> objList = _db.Boradcast.ToList();
to replace
IEnumerable<Broadcast> objList = _db.Boradcast;

In Microsoft.AspNetCore.Mvc: Prevent _context from using cached results when initializing model

A table in my database is used to store a hierarchy. It does this by having a column represent it's parent, which is a foreign key to another row in the same table.
Another feature in this table is a column referencing a Branch.
A branch has permission to view all entries related to this entry (parent or children just not laterally).
To do this I will get all entities related to the branch and then recursively retrieve their children until I have a list of entities that don't have any children. At this point I was hoping to use 'OnModelCreating' method of DBContext to retrieve an daisy chain of objects until it reaches the top level.
This works partially. Everything works until I get to the OnModelCreating method where it retrieves parent objects until it gets to the parent object with the BranchId.
My assumption is that it uses a cached result from the line marketsUnknownChildren = await _context.Markets.Where(x => x.BranchID.Equals(brancheID)).ToListAsync();. Because the parent object has 'BranchID' set to 'null' the 'OnModelCreating' method does not find any object and leaves the parameter 'ParentMarket' as 'null'.
I've tested this by assigning various levels of the hierarchy to a branch. Each time It returns all entries which have no children and a chain of parent objects until the level that contains the branch.
How do I either:
Reload the objects with parentIds but no parentObject
or prevent the where clause from applying to the parent object
or not caching the results of the first query?
Thank you.
Market
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
namespace TenantToolVmApi.Models
{
[Table("Markets")]
public class Market
{
[Key]
public int ID { get; set; }
[Column("Branch ID")]
public int? BranchID { get; set; }
[Column("ParentId")]
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Market? ParentMarket { get; set; }
[Column("Canada_Plus_MarketsID")]
public int Canada_Plus_MarketsID {get; set;}
[Column ("Name")]
public string Name { get; set; }
}
}
MarketContext
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace TenantToolVmApi.Models
{
public class MarketContext : DbContext
{
public MarketContext(DbContextOptions<MarketContext> options)
: base(options)
{
}
public DbSet<Market> Markets { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Market>()
.HasOne(u => u.ParentMarket);
}
}
}
MarketCotroller
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TenantToolVmApi.Models;
namespace TenantToolVmApi.Controllers
{
[Authorize]
[ApiController]
[Route("[controller]")]
public class MarketsController : ControllerBase
{
private readonly MarketContext _context;
public MarketsController(MarketContext context)
{
_context = context;
}
// GET: api/Markets
[HttpGet]
public async Task<ActionResult<IEnumerable<Market>>> GetMarketsItems()
{
string userName = HttpContext.User.Identity.Name;
PermissionController permissionController = new PermissionController(userName);
if (permissionController.HasNationalScope())
return await _context.Markets.ToListAsync();
else
{
int brancheID = permissionController.GetAccessibleBranches();
IEnumerable<Market> marketsHasNoChildren = new List<Market>();
List<int> addedIds = new List<int>();
IEnumerable<Market> marketsUnknownChildren;
IEnumerable<Market> marketsToCheckOnNextPass;
IEnumerable<Market> result;
marketsUnknownChildren = await _context.Markets.Where(x => x.BranchID.Equals(brancheID)).ToListAsync();
while (marketsUnknownChildren.Count() > 0)
{
marketsToCheckOnNextPass = new List<Market>();
foreach (Market market in marketsUnknownChildren)
{
result = await _context.Markets.Where(x => x.ParentId.Equals(market.ID)).ToListAsync();
if (result.Count() > 0)
marketsToCheckOnNextPass = marketsToCheckOnNextPass.Concat(result);
else if (!addedIds.Contains(market.ID))
{
marketsHasNoChildren = marketsHasNoChildren.Concat(new List<Market> { market });
addedIds.Add(market.ID);
}
}
marketsUnknownChildren = marketsToCheckOnNextPass;
}
ActionResult<IEnumerable<Market>> returnActionResults = marketsHasNoChildren.ToList();
return returnActionResults;
}
}
private bool MarketsExists(int id)
{
return _context.Markets.Any(e => e.ID == id);
}
}
}
For your model design , it seems that there is a self-referencing one-to-one relationship in Market. And ? operator is used after a non-nullable simple type , not complex type. Refer to the below code:
[Table("Markets")]
public class Market
{
[Key]
public int ID { get; set; }
[Column("Branch ID")]
public int? BranchID { get; set; }
[Column("ParentId")]
public int? ParentId { get; set; }
[ForeignKey("ParentId")]
public virtual Market ParentMarket { get; set; }
[Column("Canada_Plus_MarketsID")]
public int Canada_Plus_MarketsID { get; set; }
[Column("Name")]
public string Name { get; set; }
}
modelBuilder.Entity<Market>()
.HasOne(u => u.ParentMarket)
.WithOne()
.HasForeignKey<Market>(u => u.ParentId)
.IsRequired(false);
And then you can use Include() method to load the related data
await _context.Markets.Include(m=>m.ParentMarket).Where(x => x.BranchID.Equals(brancheID)).ToListAsync();
Result

Exception while retrieving data using Entity framework (Code first)

I am not sure what the protocol is w.r.t. to changing your question but I guess it would be better if I change it as there is a lot of information and the original intent of asking the question has been lost.
Original question:
I was originally having an issue while generating a database using EF (Code first approach / POCO classes).
One of the issues was that I was making use of Constructors in my entity classes to initialize the members. After #RickStahl suggested that it is not required, I changed my implementation.
For the sake of readers, I didn't want the information to be lost as some of the old comments intend to adress that issue.
However, during the course of time since this thread was initially created, the situation has changed. I have been able to get over some of the issues.
Current Issue:
I am having problem retrieving the content from the underlying database tables.
Exception:
Object reference not set to an instance of an object.
The exception occurs at the following statement of Program.cs (Line 21):
foreach(PhoneNumber p in cd.Phones)
For the sake of ease in understanding the issue, I am pasting the whole source code.
Here's the source code of my Entity class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ConsoleApplication1
{
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
}
public class PhoneNumber
{
[Key]
public int PhoneId { get; set; }
public int ContactId { get; set; }
public string Phone { get; set; }
public ContactData ContactData { get; set; }
public PhoneNumber()
{
}
}
public class EmailAddress
{
[Key]
public int EmailId { get; set; }
public int ContactId { get; set; }
public string Email { get; set; }
public ContactData ContactData { get; set; }
public EmailAddress()
{
}
}
}
ContactContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity;
namespace ConsoleApplication1
{
public class ContactContext : DbContext
{
public ContactContext()
: base("ContactDBContext")
{
Database.SetInitializer<ContactContext>(new DropCreateDatabaseIfModelChanges<ContactContext>());
}
public DbSet<ContactData> Contacts { get; set; }
}
}
ContactManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
cListData = cContactList.ToList();
return cListData;
}
}
}
Program.cs (Entry point)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main()
{
ContactManager cMgr = new ContactManager();
foreach (ContactData cd in cMgr.GetContactList())
{
Console.WriteLine(cd.ContactId);
Console.WriteLine(cd.FirstName);
Console.WriteLine(cd.LastName);
foreach(PhoneNumber p in cd.Phones)
{
Console.WriteLine(p.Phone);
}
foreach (EmailAddress e in cd.Emails)
{
Console.WriteLine(e.Email);
}
}
Console.ReadKey();
}
I finally managed to find a solution to my own problem. But I want to extend my 'Thanks' to both #SteveGreene and #RickStahl for their valuable inputs.
#RickStahl gave a good input or recommendation of not making use of parameterized constructors in my Entity classes. Per Rick, the parameterized constructors do not work with EF.
#SteveGreene - I finally realized that you were pointing me into right direction. I was not able to get it at that time due to my lack of understanding of EF. However, after reading about the EF in detail and in particular about Eager loading and Lazy loading helped me finally.
The error related to 'Object reference not set to an instance of an object' was easy to resolve after I figured out that I had to instantiate the collection properties for 'Phones' and 'Emails' in the ContactData class constructor.
Please refer to the code change below.
public class ContactData
{
[Key]
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string BusinessName { get; set; }
public IList<PhoneNumber> Phones { get; set; }
public IList<EmailAddress> Emails { get; set; }
public ContactData()
{
//By instantiating Phones and Emails member collections below, resolved 'Object reference not set to an instance of an object' exception
Phones = new List<PhoneNumber>();
Emails = new List<EmailAddress>();
}
}
The next step was to populate data into related Entities as I was only able to populate the parent Entity Contact up to this point.
For that I had to discover from my research and understand about different approaches such as Eager loading, Lazy loading etc. towards loading data into related entities.
That is done by using the following statements in the ContactManager.GetContactList() method. I have used eager loading method as far as I understand. For lazy loading, you have to use virtual members for child classes such as Phone and Email in this case.
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
Here's a complete code of ContactManager class.
class ContactManager
{
ContactContext cDbContext = new ContactContext();
public IList<ContactData> GetContactList()
{
ContactData cd = new ContactData();
IQueryable<ContactData> cContactList = cDbContext.Contacts;
IList<ContactData> cListData = new List<ContactData>();
var phones = cDbContext.Contacts.Include("Phones").ToList();
var emails = cDbContext.Contacts.Include("Emails").ToList();
cListData = cContactList.ToList();
return cListData;
}
}
After learning about this I understood that #SteveGreene was pointing me into correct direction. Only issue that I ran into after all this was that I used a lambda expression with Include method. But I got a compile time exception 'Include method expects a string'. I tried using the following lambda expression with the include method.
var phones = cDbContext.Contacts.Include(b => b.Phones).ToList(); // this was causing a compile time error 'Include method expects a string'.
After passing (as below) the name of the parameter as string with the name of 'Phones' and 'Emails' collection members of ContactData class, it worked fine.
var emails = cDbContext.Contacts.Include("Emails").ToList();
If any queries then please post a comment.

Fluent NHibernate Automap error while mapping XmlDocument Column

I am new to NHibernate and am facing some issues with Fluent NHibernate automap.
I am using Nhibernate 3.3.3.400, Fluent Nhibernate 1.3.0.733 Automapper 2.2.1
I have a column in Database which is of type Xml. When I try to create a ma mapping column it give me the following error.
An association from the table Product refers to an unmapped class: System.Xml.XmlDocument
Following is the code I am trying to implement.
using System.Collections.Generic;
using System.Xml;
//using System.Xml.Linq;
namespace Examples.FirstAutomappedProject.Entities
{
public class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; set; }
public virtual double Price { get; set; }
public virtual Location Location { get; set; }
public virtual IList<Store> StoresStockedIn { get; set; }
public virtual XmlDocument SalesRange { get; set; }
public Product()
{
StoresStockedIn = new List<Store>();
}
}
}
I have been struggling for a couple of days now anhy help or samples would be greatly appreciated.
it seems it FNH will not map it on it's own. you'll need a Override there
Map(x => x.SalesRange).CustomType<NHibernate.Type.XmlDocType>();
Since Firo has sent his answer in comment I am answering it on his behalf.
basically here is what I ended up doing.
I created an override class as follows
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
using Examples.FirstAutomappedProject.Entities;
using NHibernate.Mapping;
using NHibernate.Type;
namespace Examples.FirstAutomappedProject.Overrides
{
public class OrderQueueOverride : IAutoMappingOverride<Product>
{
public void Override(AutoMapping<Product> mapping)
{
mapping.Map(x => x.SalesRange).CustomType<XmlDocType>();
}
}
}
So the auto mapper will pick this override and map the column accodingly.