Dapper MultiMapping not working - c#

I'm trying to create a List of object Work using Dapper to do the mapping.
This is the code:
public class Work
{
public int id { get; set; }
public int id_section { get; set; }
public decimal price { get; set; }
public Model id_model { get; set; }
public Type id_type { get; set; }
}
class Model
{
public int id_model { get; set; }
public string Name { get; set; }
}
class Type
{
public int id_type { get; set; }
public string Name { get; set; }
}
public List<Work> GetListOfWork(int idList)
{
using (DatabaseConnection db = new DatabaseConnection()) //return a connection to MySQL
{
var par = new {Id = idList};
const string query = "SELECT id,id_section,price,id_model,id_type FROM table WHERE id_section = #Id";
return db.con.Query<Work, Model, Type, Work>(query,
(w, m, t) =>
{
w.id_model = m;
w.id_type = t;
return w;
}, par, splitOn: "id_model,id_type").ToList();
}
}
It doesn't give me any error but id_model and id_type in my the returned List are always empty (The object are created but all the fields are empty or null), other fields are mapped correctly.
Any clue ?

You need to add yourself the joins in the query string
Probably it is something like this
var par = new {Id = idList};
const string query = #"SELECT w.id,w.id_section,w.price,
m.id_model, m.Name, t.id_type, t.Name
FROM work w INNER JOIN model m on w.id_model = m.id_model
INNER JOIN type t on w.id_type = t.id_type
WHERE w.id_section = #Id";
return db.con.Query<Work, Model, Type, Work>(query,
(w, m, t) =>
{
w.id_model = m;
w.id_type = t;
return w;
}, par, splitOn: "id_model,id_type").ToList();

Related

Filter data from 2 lists with diferent models C#

I have this models
public class RoutingAttributeModel
{
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
public string Notes { get; set; }
}
public class AgentRoutingAttributeModel
{
public int Agent_No { get; set; }
public int Bus_No { get; set; }
public int Attribute_No { get; set; }
public string Attribute_Name { get; set; }
public string Status { get; set; }
}
List<RoutingAttributeModel> lstComplete = new List<RoutingAttributeModel>();
List<AgentRoutingAttributeModel> lstAssigned = new List<AgentRoutingAttributeModel>();
Filled this with some data
Is it possible to filter with Linq? I want to save in a new list the diferent content between lstComplete and lstAssigned
I was trying to join both lists but got stuck there
var results1 = from cl in lstComplete
join al in lstAssigned
on cl.Attribute_No equals al.Attribute_No
select cl;
you can use linq
as my understanding, you try to find linked by attribute_No records and have a list of not matching properties?
lstComplete.Add(new RoutingAttributeModel(){
Attribute_Name = "aaa",
Attribute_No = 1,
Bus_No = 1,
Notes = "",
Status = "status"
});
lstAssigned.Add(new AgentRoutingAttributeModel()
{
Attribute_No = 1,
Agent_No = 10,
Bus_No = 1,
Attribute_Name = "bbb",
Status = "status2"
});
var lst = lstComplete
.Join(lstAssigned,
complete => complete.Attribute_No,
assigned => assigned.Attribute_No,
(complete, assigned) => new { lstComplete = complete, lstAssigned = assigned })
.Select(s => new { s.lstComplete, s.lstAssigned})
.Where(w=>
w.lstAssigned.Attribute_Name != w.lstComplete.Attribute_Name
|| w.lstAssigned.Bus_No != w.lstComplete.Bus_No
)
.ToList()
.Dump();
so result would be
You could try the following query
var filteredList = lstComplete
.Where(x => !lstAssigned.Any(y => y.Attribute_No == x.Attribute_No));

Returning a List<> inheritance C#

class cuentaBancaria
{
public cuentaBancaria()
{
}
public cuentaBancaria(string nombreCliente, string numCuenta, double tipoInteres, double saldo)
{
this.nombreCliente = nombreCliente;
this.numCuenta = numCuenta;
this.tipoInteres = tipoInteres;
this.saldo = saldo;
}
public string nombreCliente { get; set; }
public string numCuenta { get; set; }
public double tipoInteres { get; set; }
public double saldo { get; set; }
public static List<cuentaBancaria> cuentas = new List<cuentaBancaria>()
{
new cuentaBancaria ("John Doe", "123456", 1.5, 159),
new Tarjeta ("John Doe", "123456" , 1.5, 159, "123456789012", "John Doe", TipoTarjeta.CREDITO)
};
}
TipoTarjeta:
enum TipoTarjeta
{
CREDITO,
DEBITO,
MONEDERO,
FINANCIACION
}
Tarjeta:
class Tarjeta : cuentaBancaria
{
public Tarjeta()
{
}
public Tarjeta(string nombreCliente, string numCuenta, double tipoInteres, double saldo, string numTarjeta, string nombre, TipoTarjeta tipoTarjeta)
{
base.nombreCliente = nombreCliente;
base.numCuenta = numCuenta;
base.tipoInteres = tipoInteres;
base.saldo = saldo;
this.numTarjeta = numTarjeta;
this.nombre = nombre;
this.tipoTarjeta = tipoTarjeta;
}
public string numTarjeta { get; set; }
public string nombre { get; set; }
public TipoTarjeta tipoTarjeta { get; set; }
}
I want to return the elements that has a TipoTarjeta.XXX but when I try the
cuentas.Where(c => c.tipoTarjeta == tipo)
I get the error that is an element of the child (Tarjeta) not cuentaBancaria.
How can I only get those elements with that type?
You have a type mismatch.
Your function is declared such that it returns List<cuentaBancaria>, but Where is a LINQ extension method that returns an IEnumerable<cuentBancaria>.
To resolve your issue, add a call to the ToList() extension method as follows:
cuentas.Where(c => c.tipoTarjeta == tipo).ToList()
UPDATE
I copied your code to VSCode and this version of Main works for me. From what I could tell, you needed to reference cuentas through cuentaBancaria; also, the property you were referencing in the Where clause was incorrect, based on the class definition.
public static void Main()
{
var tipo = 3.15;
var result = cuentaBancaria.cuentas.Where(c => c.tipoInteres == tipo).ToList();
foreach (var item in result)
{
Console.WriteLine(item.tipoInteres);
}
}
You first need to filter the list to only the types of Tarjeta, and then you can filter by properties of Tarjeta. You can do this using .OfType<T>() in LINQ:
cuentas.OfType<Tarjeta>().Where(c => c.tipoTarjeta == tipo)

Add values to a list inside a list Linq

I am having a class like this.
public class CameraModel
{
public int JobId { get; set; }
public int ViewId { get; set; }
public Guid ViewGuid { get; set; }
public string Name { get; set; }
public int ViewNum { get; set; }
public int LayoutID { get; set; }
public List<CameraViewItemModel> CameraViewItems { get; set; }
}
The CameraViewItemModel class is like this:
public class CameraViewItemModel
{
public int JobID { get; set; }
public Guid ViewGuid { get; set; }
public int ViewID { get; set; }
public int CamNum { get; set; }
public Guid ChannelGuid { get; set; }
public string Name { get; set; }
public ActionType Action { get; set; }
}
Now, I am assigning the list of CameraViewItemModel like this:
// get all the cameramodel's
cameraModels = _unitOfWork.Context.CameraViews.Where(m => m.JobId == siteId)
.Select(m => new CameraModel
{
JobId = m.JobId,
ViewId = m.ViewId,
ViewGuid = m.ViewGuid,
Name = m.Name,
ViewNum = m.ViewNum,
LayoutID = m.LayoutId
}).ToList();
// get all the cameraviewitemmodels
cameraViewItemModels =
(from cameraView in _unitOfWork.Repository<CameraViews>().Get(x => x.JobId == siteId).Result
join cameraViewItem in _unitOfWork.Repository<CameraViewItems>().Get(x => x.JobId == siteId)
.Result on cameraView.ViewId equals cameraViewItem.ViewId into CameraViewItemResults
from cameraViewItemResult in CameraViewItemResults.DefaultIfEmpty()
join cameraChannel in _unitOfWork.Repository<CameraChannels>().Get(x => x.JobId == siteId)
.Result on (cameraViewItemResult == null ? new Guid() : cameraViewItemResult.ChannelGuid) equals cameraChannel.ChannelGuid into CameraChannelResults
from cameraChannelResult in CameraChannelResults.DefaultIfEmpty()
select new CameraViewItemModel
{
JobID = cameraView.JobId,
ViewID = cameraView.ViewId,
ViewGuid = cameraView.ViewGuid,
CamNum = cameraViewItemResult.CamNum,
ChannelGuid = cameraChannelResult.ChannelGuid,
Name = cameraChannelResult.Name
}).ToList();
// then do a 'join' on JobId, ViewId and ViewGuid and assign the list of cameraviewitemmodels to cameraModels.
foreach (var cameraModel in cameraModels)
{
cameraModel.CameraViewItems = (from cameraViewItem in cameraViewItemModels
where cameraModel.JobId == cameraViewItem.JobID
&& cameraModel.ViewId == cameraViewItem.ViewID
&& cameraModel.ViewGuid == cameraViewItem.ViewGuid
select cameraViewItem).ToList();
}
return cameraModels;
There are three tables in database:
CameraViews, CameraViewItems, CameraChannels.
CameraViews is the main table. It is left joined with CameraViewItems and CameraChannels to get the desired result. There may not be any data in CameraViewItems and CameraChannels for a corresponding CameraView.
Is it possible to assign the list of CameraViewItemModels to CameraModels in a single linq statement.
Here is a simple way to add values to a sub list, dunno if this is what you mean. You can keep selecting sub lists if that is necessary.
var parent_lst = new List<List<string>>(); // Root/parent list that contains the other lists
var sub_lst = new List<string>(); // Sub list with values
var selected_parent_lst = parent_lst[0]; // Here I select sub list, in this case by list index
selected_parent_lst.Add("My new value"); // And here I add the new value

Adding multimap children into parent with Dapper

I have a very simple test project where I am trying to figure out how to add children into the parent's collection.
The datamodel is quite basic:
Current result returns a duplicated entry.
Expected/desired
I expected the result to be just one entry with two children
GROUP1 -> { USER_1, USER_2 }
GROUP class
public class GROUP
{
public GROUP()
{
this.USERs = new HashSet<USER>();
}
public int Group_ID { get; set; }
public string Name { get; set; }
public string Location { get; set; }
public ICollection<USER> USERs { get; set; }
}
USER class
public class USER
{
public int User_ID { get; set; }
public int Group_ID { get; set; }
public string Name { get; set; }
public Nullable<int> Age { get; set; }
public GROUP GROUP { get; set; }
}
Dapper method
public GROUP Get(int id)
{
string sqlGetGroupExtended = $"SELECT _group.Group_ID, _group.Name, _group.Location, _user.User_ID, _user.Name, _user.GROUP_ID, _user.Age FROM dbo.[GROUP] _group " +
"LEFT JOIN dbo.[USER] _user ON _group.Group_ID = _user.Group_ID " +
"WHERE _group.Group_ID = #groupid;";
GROUP result = null;
var lookup = new Dictionary<int, GROUP>();
using (var connection = new SqlConnection(Properties.Settings.Default.CodeTest_DB))
{
var extendedGroup = connection.Query<GROUP, USER, GROUP>(sqlGetGroupExtended, (parent, child) =>
{
if (!lookup.TryGetValue(parent.Group_ID, out GROUP found))
{
lookup.Add(parent.Group_ID, found = parent);
}
found.USERs.Add(child);
return found;
}, param: new { groupid = id }, splitOn: "Location");
// result = extendedGroup <--- WHAT TO DO HERE?
}
return result;
}
How can I achieve this?
References:
http://dapper-tutorial.net/dapper
https://github.com/StackExchange/Dapper/blob/master/Dapper.Tests/MultiMapTests.cs#L12
If you're using SQL Server 2016 or Azure SQL you can take advance of JSON to return a hierarchical object:
https://medium.com/dapper-net/one-to-many-mapping-with-dapper-55ae6a65cfd4
It's an article I wrote on the subject, along with source code, that shows how to elegantly solve the problem.
My bad, as the code shows here https://github.com/StackExchange/Dapper/blob/master/Dapper.Tests/MultiMapTests.cs#L12
I was missing the .Distinct()
var extendedGroup = connection.Query<GROUP, USER, GROUP>(sqlGetGroupExtended, (parent, child) =>
{
if (!lookup.TryGetValue(parent.Group_ID, out GROUP found))
{
lookup.Add(parent.Group_ID, found = parent);
}
found.USERs.Add(child);
return found;
}, param: new { groupid = id }, splitOn: "Location,User_ID").Distinct();

Cannot implicitly convert type 'System.Collections.Generic.List<AnonymousType#1>' to 'System.Collections.Generic.List<FirstApp.Model.TeamDetails>

I am getting this error
Cannot implicitly convert type
System.Collections.Generic.List<AnonymousType#1> to
System.Collections.Generic.List<FirstApp.Model.TeamDetails>
What's wrong with my code?
Here is my code
TeamDetails Class
public class TeamDetails
{
[Key]
public int TeamId { get; set; }
public string TeamName { get; set; }
public string Description { get; set; }
public int? UserCount { get; set; }
}
ViewModel
public class ViewTeamList
{
public List<TeamDetails> TeamNext { get; set; }
}
Controller
public ActionResult Next(int dataid)
{
ViewTeamList viewTeamList = new ViewTeamList();
var a = from t in tDbContext.Teams
join u in tDbContext.Users on t.TeamId equals u.TeamId into g
where t.Deleted != true
select new { TeamId= t.TeamId,TeamName = t.TeamName, Description = t.Description, UserId = g.Count() };
var next = a.OrderBy(t1 => t1.TeamId).Where(t1 => t1.TeamId > dataid).FirstOrDefault();
viewTeamList.TeamNext = a.ToList();
return PartialView("_ViewTeamDetails", viewTeamList);
}
I'm not able to assign this value to
viewTeamList.TeamNext = a....;
This constructs an anonymous type instead of TeamDetails
select new { TeamId= t.TeamId,TeamName = t.TeamName, Description = t.Description, UserId = g.Count() }
You should change it to below
select new TeamDetails { TeamId = t.TeamId, TeamName = t.TeamName, Description = t.Description, UserCount = g.Count() }
so a.ToList() would be a List<FirstApp.Model.TeamDetails>

Categories