I have a stored procedure that returns rows consisting of a join on Po header and Po Detail tables (so Po Header info is repeated in each child Po detail). My repository method maps this combined info into a Po object where each header info is repeated for every associated PO detail. Is there a best way to map these Po objects into a PO Header with a list of PO details?
Edit: I'm using Dapper for ORM
Second Edit: I added my repo method
public class Po
{
public string HeaderField1 { get; set; }
public string HeaderField2 { get; set; }
public int HeaderField3 { get; set; }
public string DetailField1 { get; set; }
public string DetailField2 { get; set; }
public int DetailField3 { get; set; }
}
to
public class Po_Header
{
public string HeaderField1 { get; set; }
public string HeaderField2 { get; set; }
public int HeaderField3 { get; set; }
List<Po_Detail> PoDetails { get; set; }
}
public class Po_Detail
{
public string DetailField1 { get; set; }
public string DetailField2 { get; set; }
public int DetailField3 { get; set;
}
Repo Method:
public IEnumerable<Po> GetAllPosByCustomer(string customerId)
{
try
{
using (var connection = (SqlConnection) _dbFactory.GetConnection())
{
var query = "dbo.spPo_GetAllByCustomerId";
var list = SqlMapper.Query<Po>(connection, query, param: new { #CustomerId = customerId }, commandType: CommandType.StoredProcedure);
return list;
}
}
catch(Exception e)
{
var err = e.ToString();
return null;
}
}
So I have a query that returns values from multiple tables with a left join.
But I can't seem to get the data from left join table.
public IEnumerable<TipsTricks> GetTipsTricks()
{
using(var connection = new SqlConnection(Connection.Instance.ConnectionString))
{
return connection.Query<TipsTricks>(#"SELECT tt.ID, cat.Omschrijving, tt.Info, tt.Onderwerp, tt.Firma FROM tblTipsAndTricks as tt
LEFT JOIN tblTT_Categorieen as cat on cat.Id = tt.CategorieID ");
}
}
I then do in code behind to bind it to Datagrid.ItemsSource:
public void initialize()
{
List<TipsTricks> tipstricks = DatabaseManager.Instance.TipsTricksRepository.GetTipsTricks().ToList();
DgTipsTricks.ItemsSource = tipstricks;
}
Class TipsTricks
public class TipsTricks
{
public int Id { get; set; }
public string Info { get; set; }
public string Onderwerp { get; set; }
public string Firma { get; set; }
string Omschrijving { get; set; }
}
Also tried the binding in de XAML without succes.
So I would like a column in the datagrid showing the content of cat.Omschrijving from the left join table tblTT_Categorieen.
Thanks!
Try making the property string Omschrijvin "public"
as shown below
public class TipsTricks
{
public int Id { get; set; }
public string Info { get; set; }
public string Onderwerp { get; set; }
public string Firma { get; set; }
public string Omschrijving { get; set; }
}
I have the post method which creates a new cream
public ActionResult CreateCream(CreamModel cream, string creamTypeId)
{
if (ModelState.IsValid)
{
if (creamTypeId != string.Empty)
{
try
{
cream.CreamTypeModel_id = int.Parse(creamTypeId);
creamManager.CreateCream(cream);
TempData["message"] = string.Format("Игрок {0} сохранен", cream.Name);
return RedirectToAction("Index", "Home");
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
}
ViewBag.ChoosingCreamType = GetCreamSelectList();
return View(cream);
}
when I call
public void CreateCream(CreamModel newCream)
{
if (newCream.Id == 0)
{
context.CreamModels.Add(newCream);
context.SaveChanges();
}
}
when I call context.SaveChanges() the code fails and I go to View, instead of redirect! I don't understand why it doesn't work? If i delete SaveChanges() it executes, but doesn't save in database.
my model
public class CreamModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ImageName { get; set; }
public int? CreamTypeModel_id { get; set; }
public CreamTypeModel CreamTypeModel { get; set; }
}
error message
SqlException: The column name 'CreamTypeModel_id' is specified more
than once in the SET clause or column list of an INSERT. A column
cannot be assigned more than one value in the same clause. Modify the
clause to make sure that a column is updated only once. If this
statement updates or inserts columns into a view, column aliasing can
conceal the duplication in your code.
The issue that comes to mind is that you have a relationship without associating the FK:
public class CreamModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ImageName { get; set; }
[ForeignKey("CreamTypeModel")]
public int? CreamTypeModel_id { get; set; }
public virtual CreamTypeModel CreamTypeModel { get; set; }
}
This links up the FK to the associated reference property.
I am fairly new to asp.net mvc and I currently have an application that shows a number of errors. I have 2 pages that contain Application Errors and Log Errors. The data comes from 2 different databases but I am wanting to display the data from both databases on one page.
The tables have headings with different names that mean the same thing e.g. ApplicationName in the Application Database is the same thing as LogName in the Log Database.
Below is a small example of what I currently have and an example of what I am wanting.
Current
Application Errors
ID ApplicationName ApplicationMessage ApplicationDate
1 Something Hello World 01/01/2015
2 Something Else Another Message 03/01/2015
Log Errors
ID LogName LogMessage LogDate
1 Some Log A log message 02/01/2015
2 Another Log Another Log Message 04/01/2015
What I Want
Internal Errors
ID Name Message Date
1 Something Hello World 01/01/2015
2 Some Log A log message 02/01/2015
3 Something Else Another Message 03/01/2015
4 Another Log Another Log Message 04/01/2015
At the minute, I have 2 separate models for each database but I think I need to merge both models into one model that combines them both but I am unsure on how to do this. How would I be able to merge both data sources together to display the data within the same page?
Current Models
Application
[Table("ELMAH_Error")]
public class ElmahError
{
[Key]
public System.Guid ErrorId { get; set; }
public System.String Application { get; set; }
public System.String Host { get; set; }
public System.String Type { get; set; }
public System.String Source { get; set; }
public System.String Message { get; set; }
public System.String User { get; set; }
public System.Int32 StatusCode { get; set; }
public System.DateTime TimeUtc { get; set; }
public System.Int32 Sequence { get; set; }
public System.String AllXml { get; set; }
}
Log
[Table("LogEntry")]
public class LogEntry
{
[Key]
public Int64 ID { get; set; }
public DateTime LogDate { get; set; }
public Int16 Priority { get; set; }
public string SourceClass { get; set; }
public string Category { get; set; }
public string Message { get; set; }
public string UserID { get; set; }
public string ProcessID { get; set; }
}
From the models, there are a number of fields that I would like to merge as well as fields that are not similar that I would also like to include. The model below shows exactly what I want but I just don't know how to implement it.
Internal Errors
public class InternalErrors
{
public string Id { get; set; } //L:ID && E:ErrorId
public int Priority { get; set; } //L:Priority
public string Application { get; set; } //L:SourceClass && E:Application
public string Message { get; set; } //L:Message && E:Message
public string Type { get; set; } //L:Category && E:Type
public string User { get; set; } //L:UserID && E:User
public string ProcessID { get; set; } //L:ProcessID
public DateTime Date { get; set; } //L:LogDate && E:TimeUtc
public int StatusCode { get; set; } //E:StatusCode
public string AllXml { get; set; } //E:AllXml
public int Sequence { get; set; } //E:Sequence
public int ErrorCount { get; set; } //E:ErrorCount
}
I hope this is enough information for you to provide an answer, if you need anything else, let me know.
Thanks in advance
if what you want is this
Internal Errors
ID Name Message Date
1 Something Hello World 01/01/2015
2 Some Log A log message 02/01/2015
3 Something Else Another Message 03/01/2015
4 Another Log Another Log Message 04/01/2015
then create a class with name InternalErrors as follows.
public class InternalErrors
{
public int ID;
public string Name;
public string Message;
public DateTime Date;
}
Now you can write a Linq Query as follows to get data from Application Errors and Log Errors and Perform union on it.
var AppErrors=from AE in _db.ApplicationErrors select AE;
var LogErrors=from LE in _dc.LogErrors select LE;
var internerrors=AppErrors.Union(LogErrors);
var InternalErrors=(from ie in internerrors select new InternalErrors()
{
ID=ie.ID,
Message=ie.ApplicationMessage,
Name=ie.ApplicationName,
Date=ie.ApplicationDate
}).ToList();
The viewmodel approach from MRebati is the best solution.
I often find it usefull to have a base class and different implementations:
public abstract class ErrorViewModel
{
public abstract int Id { get; }
public abstract string Name { get; }
}
public class ElmahErrorViewModel
{
public ElmahErrorViewModel(ElmahError instance)
{
this.Instance = instance;
}
public ElmahError Instance { get; private set; }
public int Id { get { return Instance.ErrorId; } }
public string Name { get { return instance.Appication; } }
}
that way you can create a List<ErrorViewModel> and add entries with
var items = from e in context.ElmahErrors
select new ElmahErrorViewModel(e);
list.AddRange(items);
var items2 = from l in context.LogEntrys
select new LogEntryViewModel(l);
list.AddRange(items2);
This is very usefull since you hide the details but you still can seprate the list and access the underlying object with
var elmahErrors = items.OfType<ElmahErrorViewModel>().Select(x => x.Instance);
There are many ways to provide data from the models to the View.
One is the ViewModel. It must contain the data you want to send to view. Look at this:
using System;
public class ErrorViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Message { get; set; }
public DateTime Date { get; set; }
}
And in the Controller you need to Create a list of this ViewModel and populate it with your data.
you can use linq
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var elmahErrorList = new List<ElmahError>{
new ElmahError{ ErrorId = Guid.NewGuid(), Application = "Something",Message = "Hello World" , TimeUtc = DateTime.Now },
new ElmahError{ ErrorId = Guid.NewGuid(), Application = "Something Else",Message = "Another Message" , TimeUtc = DateTime.Now }
};
var logEntryList = new List<LogEntry>{
new LogEntry{ ID = 1, SourceClass = "Something",Message = "Hello World" , LogDate = DateTime.Now },
new LogEntry{ ID = 1, SourceClass = "Something Else",Message = "Another Message" , LogDate = DateTime.Now }
};
var internalErrorsList = new List<InternalErrors>();
var elmahErrorListinternalErrorses = elmahErrorList.Select(e => new InternalErrors
{
Id = e.ErrorId.ToString(),
Application = e.Application,
Message = e.Message,
Type = e.Type,
User = e.User,
Date = e.TimeUtc,
StatusCode = e.StatusCode,
AllXml = e.AllXml,
Sequence = e.Sequence
});
internalErrorsList.AddRange(elmahErrorListinternalErrorses);
var elmahErrorListlogEntryLists = logEntryList.Select(l => new InternalErrors
{
Id = l.ID.ToString(),
Priority = l.Priority,
Application = l.SourceClass,
Message = l.Message,
Type = l.Category,
User = l.UserID,
Date = l.LogDate
});
internalErrorsList.AddRange(elmahErrorListlogEntryLists);
internalErrorsList.ForEach(f =>
{
Console.Write(f.Id); Console.Write("\t");
Console.Write(f.Application);Console.Write("\t");
Console.Write(f.Message);Console.Write("\t");
Console.Write(f.Date);Console.Write("\t");
Console.WriteLine();
});
}
public class InternalErrors
{
public string Id { get; set; } //L:ID && E:ErrorId
public int Priority { get; set; } //L:Priority
public string Application { get; set; } //L:SourceClass && E:Application
public string Message { get; set; } //L:Message && E:Message
public string Type { get; set; } //L:Category && E:Type
public string User { get; set; } //L:UserID && E:User
public string ProcessID { get; set; } //L:ProcessID
public DateTime Date { get; set; } //L:LogDate && E:TimeUtc
public int StatusCode { get; set; } //E:StatusCode
public string AllXml { get; set; } //E:AllXml
public int Sequence { get; set; } //E:Sequence
public int ErrorCount { get; set; } //E:ErrorCount
}
public class ElmahError
{
public System.Guid ErrorId { get; set; }
public System.String Application { get; set; }
public System.String Host { get; set; }
public System.String Type { get; set; }
public System.String Source { get; set; }
public System.String Message { get; set; }
public System.String User { get; set; }
public System.Int32 StatusCode { get; set; }
public System.DateTime TimeUtc { get; set; }
public System.Int32 Sequence { get; set; }
public System.String AllXml { get; set; }
}
public class LogEntry
{
public Int64 ID { get; set; }
public DateTime LogDate { get; set; }
public Int16 Priority { get; set; }
public string SourceClass { get; set; }
public string Category { get; set; }
public string Message { get; set; }
public string UserID { get; set; }
public string ProcessID { get; set; }
}
}
Demo : https://dotnetfiddle.net/mrWGDn
This a simple project where users can search for job postings by area of expertise. The relationship between Areas and Postings are Many-to-many. I seem to be able to get to the very last part of retrieving the correctly filtered list, but getting back into the view model keeps giving me different errors:
ViewModel:
public class AreaOfertasViewModel
{
public Oferta UnaOferta { get; set; }
public SelectList AreasTrabajo { get; set; }
public IEnumerable<Oferta> Ofertas { get; set; }
public int idArea { get; set; }
public AreaOfertasViewModel()
{
this.UnaOferta = UnaOferta;
this.Ofertas = new List<Oferta>();
cargarAreas();
}
private void cargarAreas()
{
PostulaOfertaContext db = new PostulaOfertaContext();
this.AreasTrabajo = new SelectList(db.Areas, "areaId", "Area");
}
}
}
Controller:
public ActionResult SearchXArea()
{
return View(new AreaOfertasViewModel());
}
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id);
var ofertas = from c in db.Ofertas.Where(r => r.AreaTrabajo == area)
select c;
aovm.Ofertas = (IEnumerable<Oferta>)ofertas.ToList();
return View(aovm);
}
The line giving me issues is
aovm.Ofertas = (IEnumerable)ofertas.ToList();
I've tried List<> for Ofertas, and I've tried leaving it as .ToList() without casting, and casting it as different things, but it gives me errors about not being able to cast it, and "Cannot compare elements of type 'System.Collections.Generic.List`1'. Only primitive types, enumeration types and entity types are supported."
What's the solution here?
Model for AreaTrabajo:
public class AreaTrabajo
{
[Key]
public int areaId { get; set; }
public string Area { get; set; }
public virtual List<Oferta> oferta { get; set; }
}
Model for Oferta:
public class Oferta
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Titulo { get; set; }
[Required]
public DateTime Vencimiento { get; set; }
[Required]
public string Cargo { get; set; }
[Required]
public int HorarioComienzo { get; set; }
[Required]
public int HorarioFin { get; set; }
[Required]
public string DescripcionTareas { get; set; }
public int Remuneracion { get; set; }
[Required]
public int RangoEdadMin { get; set; }
[Required]
public int RangoEdadMax { get; set; }
public string TipoFormacion { get; set; }
public string Idiomas { get; set; }
public string Competencias { get; set; }
public string OtrosEstudios { get; set; }
public string Estado { get; set; }
public virtual List<AreaTrabajo> AreaTrabajo { get; set; }
public virtual TipoContrato TipoContrato { get; set; }
public virtual Empresa Empresa { get; set; }
public virtual List<Postulante> Postulantes { get; set; }
}
Answer
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I needed to filter out from the many-to-many relationship, and this solved it.
You are getting an error because the actual sql is executed when you call tolist(). The error is in your sql because you are comparing AreaTrabago to a list.
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I couldn't get the many-to-many relationship, and this solved the filtering problem perfectly.