Home > OS >  How do I reference fields from a lookup table using FromSqlRaw in Entity Framework Data First?
How do I reference fields from a lookup table using FromSqlRaw in Entity Framework Data First?

Time:12-30

I have reviewed numerous articles here that seem similar, but none address the topic of returning data from multiple tables (lookup table for example) using the FromSqlRaw method of a dbSet.

The tables in question - SlotData and Slotdenom . are related in the SQL database using a foreign key and I generated the data models using NuGet. The Details() task of the controller results in useful data begin sent to the views but the Index() task does not.

The Index method is where my dbSet.FromSqlRaw lives.

DbContext file:

modelBuilder.Entity<SlotDatum>(entity =>
{
    entity.HasKey(e => e.Id).HasName("PK_Slot_Data_1");
    entity.ToTable("Slot_Data");
    entity.HasIndex(e => e.Id, "IX_Slot_Data");

    entity.Property(e => e.CalDate)
        .HasColumnType("date")
        .HasColumnName("Cal_Date");
    entity.Property(e => e.Denom_Id).HasColumnName("Denom_ID");
    entity.Property(e => e.Drop).HasColumnType("money");
    entity.Property(e => e.Handle).HasColumnType("money");
    entity.Property(e => e.Win).HasColumnType("money");

    entity.Property(d => d.Denom_Id).HasColumnType("int");
    //entity.Property(e => e.Description).HasColumnName("Description");

    entity.HasOne(d => d.Denom).WithMany(p => p.SlotData)
        .HasForeignKey(d => d.Denom_Id)
        .HasConstraintName("FK_Slot_Data_SlotDenom");
});

SlotsDatum model class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace FlashWeb.Models.DB;

public partial class SlotDatum
{
    [Key]
    public int Id { get; set; }

    // public DateTime? CalDate { get; set; }
    public DateOnly CalDate { get; set; }

    public int? Denom_Id { get; set; }
    public decimal? Handle { get; set; }
    public decimal? Drop { get; set; }
    public decimal? Win { get; set; }
    public int? SlotCount { get; set; }

    public virtual SlotDenom? Denom { get; set; }
}

SlotDenom model class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace FlashWeb.Models.DB;

public partial class SlotDenom
{
    [Key]
    public int Denom_Id { get; set; }

    public decimal? Value { get; set; }
    public string? Description { get; set; }
    public string? Status { get; set; }
    public int? ReportOrder { get; set; }

    public virtual ICollection<SlotDatum> SlotData { get; } = new List<SlotDatum>();
}

SlotsDatum controller:

public async Task<IActionResult> Index([Bind("Id,CalDate, Handle,Drop, Win, SlotCount, Denom_id, Description, ReportOrder, [Status]")] SlotDatum slotDatum)
{
    var flashBudgetContext = _context.SlotData.Include(s => s.Denom);

    GlobalCalDate globalCalDate = new GlobalCalDate();
    globalCalDate.CalDateOnly = slotDatum.CalDate;
    ViewBag.CalDate = globalCalDate.CalDateFormatted;
    ViewBag.CalDateOnly = globalCalDate.CalDateOnly;

    // This works for SlotsData but does not return any info from SlotsDenom model even though the stored proc. includes this data
    try
    {
        if (slotDatum.CalDate != DateOnly.MinValue)// && (tblStat.CalDate != null))
            return View(await _context.SlotData.FromSqlRaw("EXEC sp_GetSlotData "   "'"   slotDatum.CalDate   "'").ToListAsync());
        else
            return View(await _context.SlotData.FromSqlRaw("EXEC sp_GetSlotsData "   "'"   DateOnly.FromDateTime(DateTime.Now)   "'").ToListAsync());
    }
    catch (Exception ex)
    {
        Problem("Entity set "   ex.Message   " "   "  is null.");
        return View(await _context.SlotData.FromSqlRaw($"sp_GetLastSlotsData").ToListAsync());
    }
}

// GET: SlotDatums/Details/5
// This works great for both SlotsData and SlotsDenom data.
public async Task<IActionResult> Details(int? id)
{
    if (id == null || _context.SlotData == null)
    {
        return NotFound();
    }

    var slotDatum = await _context.SlotData
        .Include(s => s.Denom)
        .FirstOrDefaultAsync(m => m.Id == id);

    if (slotDatum == null)
    {
        return NotFound();
    }

    return View(slotDatum);
}

Here is my SQL join:

SELECT
    Id,
    Cal_Date,
    SUM(Handle) AS 'Handle',
    SUM([Drop]) AS 'Drop', 
    SUM(Win) AS 'Win',
    SlotCount,
    denom.Denom_id,
    denom.[Description] AS 'Description',
    ReportOrder,
    [Status]
FROM
    Slot_Data sd
RIGHT OUTER JOIN
    SlotDenom denom ON denom.Denom_id = sd.Denom_id
WHERE
    denom.ReportOrder IS NOT NULL
    AND Cal_Date = @sBusDate
GROUP BY
    SlotCount, denom.Denom_id, [Description], ReportOrder, 
    [Status], Id, Cal_Date
ORDER BY 
    ReportOrder

CodePudding user response:

That's just not a feature of EF; you must have a single type that matches output of FromSqlRaw. You can open an issue here: https://github.com/dotnet/efcore/issues

  • Related