I have an IQueryable<MainObjectTest> in which there are several fields, but I only need to pull out certain ones (Title and NestedObject).
How can I do this with dynamic select expression?
public class TestIQueryable
{
public IQueryable GetObjectData(IQueryable<MainObjectTest> data)
{
IQueryable requredDataFields = data.Select("new(Title, NestedObject)");
return requredDataFields;
}
public class MainObjectTest
{
public string Title { get; set; }
public DateTime Date { get; set; }
public NestedClassTest NestedObject { get; set; }
}
public class NestedClassTest
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
}
What about making an interface:
interface Interface1
{
public string Title { get; set; }
public NestedClassTest NestedObject { get; set; }
}
Implement the interface in you class and let GetObjectData return the interface
public IQueryable GetObjectData(IQueryable<Interface1> data)
{
IQueryable requredDataFields = data.Select();
return requredDataFields;
}
I solved my problem using model, here steps:
Map all data from database into model if you have nested object => use ToList().
Use DynamicLinq library to select certain fields from model as IQueryable.
Hope it helps someone!
Use an anonymous object like this.
IQueryable requredDataFields = data.Select(x => new { x.Title, x.NestedObject });
Related
I'm trying to use a ViewModel in C# MVC .NET Visual Studio. I have this mode that's filled with data. It's built up like so:
public class Offer
{
public List<ProjectleaderModel> Projectleaders { get; set; } = new List<ProjectleaderModel>();
public List<OfferManagerModel> OfferManagers { get; set; } = new List<OfferManagerModel>();
public List<ProductModel> Products { get; set; } = new List<ProductModel>();
public List<PersonModel> People { get; set; } = new List<PersonModel>();
public string Administration { get; set; }
public string Status { get; set; }
public DateTime Applicationdate { get; set; }
public DateTime Submitdate { get; set; }
public Boolean CustomerAgreementBoolean { get; set; }
public DateTime CustomerAgreementBooleanDate { get; set; }
}
public class ProjectleaderModel
{
public int Id;
public string Name;
}
And in my viewmodel I'm trying to get data into a separate list I want to turn into a dropdown-menu:
public List<Offer> Offermodel = new List<Offer>();
public List<ProjectleaderModel> Projectleaders
{
get
{
return Offermodel.Select(x => x.Projectleaders).ToList();
}
}
The Projectleadermodel class is in the model, as you can see.
Why is it that I'm getting the error:
Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<EnqueryApp.Model.ProjectleaderModel>>' to 'System.Collections.Generic.List<EnqueryApp.Model.ProjectleaderModel>'
The line Offermodel.Select(x => x.Projectleaders) will give you a collection of Offer class objects, which then you're making a list of.
But the return type of your Projectleaders property is List<ProjectleaderModel>
So they aren't a match.
You need to create a list of Projectleaders objects to return from that property.
Essentially:
return Offermodel.SelectMany(x => x.Projectleaders).ToList();
If you want all project leaders from all offers, then use SelectMany
return Offermodel.SelectMany(x => x.Projectleaders).ToList();
Notice that Offer.Projectleaders is of type List<ProjectleaderModel>, hence your Select will yield IEnumerable<List<ProjectleaderModel>> instead of desired IEnumerable<ProjectleaderModel>. Linq has a way around that in form of SelectMany extension method.
Given that your Projectleaders can read
public List<ProjectleaderModel> Projectleaders =>
Offermodel.SelectMany(x => x.Projectleaders).ToList();
public List<Offer> Offermodel = new List<Offer>();
public List<List<ProjectleaderModel>> Projectleaders
{
get
{
return Offermodel.Select(x => x.Projectleaders).ToList();
}
}
What you're doing is trying to get a List of the Project Leaders, but Project Leaders is already a list object, so you're getting a list of a list.
If I have an object like
class Thing
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
public string D { get; set; }
}
Dapper works really well with:
return conn.QuerySingle<Thing>(
#"SELECT A, B, C, D
FROM [Thing] WHERE Id = #id", new { id });
But what if my class structure is
class Thing
{
public string A { get; set; }
public string B { get; set; }
public IEnumerable<Stuff> { get; set; }
}
class Stuff
{
public string C { get; set; }
public string D { get; set; }
}
How can I get Dapper to map to that structure, assuming the Enumerable will always contain 1 item in the Enumerable so in reality I am just representing the same data in a different way.
The Dapper tutorials I've seen are quite complex and contain subqueries, but ideally my query shouldn't change because it already returns all the data that should map to the new structure.
Any ideas?
You have to create your own Custom Type Mapper. I've written an article and some samples here:
https://medium.com/dapper-net/custom-type-handling-4b447b97c620
I am trying to get data from a table with a get request with a controller. When I make the request with a normal table (TestTable) it is ok, but if I make the request with a relational table I get the fail message:
"The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/xml; charset=utf-8'."
My controller (Mdata):
namespace ScThAsp.Controllers
{
public class MDataController : ApiController
{
public IEnumerable<Måledata> Get()
{
using (var e = new SCTHDBEntities())
{
return e.Måledata.ToList();
}
}
public TestTable Get(int id)
{
using (SCTHDBEntities entities = new SCTHDBEntities())
{
return entities.TestTable.FirstOrDefault(e => e.Id == 1);
}
}
}
}
My Table for måledata is:
public partial class Måledata
{
public int MDid { get; set; }
public Nullable<int> BBid { get; set; }
public Nullable<decimal> Måling1 { get; set; }
public Nullable<decimal> Måling2 { get; set; }
public Nullable<decimal> Måling3 { get; set; }
public Nullable<decimal> Måling4 { get; set; }
public Nullable<System.DateTime> RegTid { get; set; }
public virtual BuildBoard BuildBoard { get; set; }
}
My database looks like:
Database
See link..
I think I mayby should make a inner join with the other table connected to Måledata table - I am not sure how to do that in a EF environment.
I have really tried a lot now - hope for an answer. Thanks
Your class Måledata contains more data that you presented (it is marked as partial) and probably contains stuff related to EF. This magic stuff is not serializable. To avoid problem rewrite results to a plain object with properties you need. This object must be serializable (if contains plain properties and classes it will).
Building upon Piotr Stapp's answer you need to create a DTO (Data Transfer Object) for your Måledata which contains properties as your model, Måledata other than the EF properties. Use some sort of Mapper, maybe AutoMapper to map the required properties in your final response.
public class MaledataDTO
{
public int MDid { get; set; }
public int? BBid { get; set; }
public decimal? Måling1 { get; set; }
public decimal? Måling2 { get; set; }
public decimal? Måling3 { get; set; }
public decimal? Måling4 { get; set; }
public DateTime? RegTid { get; set; }
//... other properties
}
public IEnumerable<MaledataDTO> Get()
{
using (var e = new SCTHDBEntities())
{
var result = e.Måledata.ToList();
return Mapper.Map<List<MaledataDTO>>(result);
}
}
I found 2 solutions.
1) Solution was with Automapper (thanks Abdul). Installing automapper and a Using Automapper. Added a class called MåledataDTO : ` public class MåledataDTO
{
public int MDid { get; set; }
public int? BBid { get; set; }
public decimal? Måling1 { get; set; }
public decimal? Måling2 { get; set; }
public decimal? Måling3 { get; set; }
public decimal? Måling4 { get; set; }
public DateTime? RegTid { get; set; }
//... other properties
}
`
In my controller I used the following code
public IEnumerable<MåledataDTO> Get()
{
using (var e = new SCTHDBEntities())
{
Mapper.Initialize(config =>
{
config.CreateMap<Måledata, MåledataDTO>();
});
var result = e.Måledata.ToList();
return Mapper.Map<List<MåledataDTO>>(result);
2: In the second solution: In the picture you see the relations bewtween the tables - made in VS - but that creates a problem in the tables Get SET classes. The relation creates a Virtual object in the class - like mentioned before
public virtual BuildBoard BuildBoard { get; set; }
If you delete the relations and make the public partial class Måledata like
in this video
https://www.youtube.com/watch?v=4Ir4EIqxYXQ
the controller should then have one of two solutions:
using (SCTHDBEntities e = new SCTHDBEntities()) {
//this works
//var knud = new List<Måledata>();
//knud = (e.BuildBoard.Join(e.Måledata, c => c.BBid, o => o.BBid,
// (c, o) => o)).ToList();
//return knud;
//this works too
return (from p in e.BuildBoard
where p.BBid == 1
from r in e.Måledata
where r.BBid == p.BBid
select p).ToList();
That was that
Gorm
I have an Generic Abstract Class with some properties like Id, Name, Status, this class inherits several catalogs.
My question is whether it is possible to create a method with a restriction for the catalogs that implement the Abstract Class.
I give some examples so that they understand what I want to do:
public abstract class AbsCatalog<T>
{
public T Id { get; set; }
public string Name { get; set; }
public bool Status { get; set; }
}
These are the classes that implement the abstract class
public class Agent : AbsCatalog<string>
{
public string Office { get; set; }
public Estado Estado { get; set; }
}
public class Models : AbsCatalog<int>
{
public int Year { get; set; }
public string Description { get; set; }
}
The method I want to implement is the following:
List<Agent> Agents = service.GetAgents();
string AgentsDescription = GetDescription<Agent>(Agents);
List<Model> Models = service.GetModels();
string ModelsDescription = GetDescription<Model>(Models);
private string GetDescription<T>(List<T> list) where T : AbsCatalog<T>
{
string description = string.Empty;
if (list.Exists(x => x.Id.ToString() == "0"))
description = "";
else
description = string.Join(", ", list.Where(x => x.Status).Select(x => x.Name).ToArray());
return description;
}
I think the only way is to use two generic type parameters here, for example:
private string GetDescription<T, U>(List<T> list) where T : AbsCatalog<U>
{
//snip
}
And then call it like this:
string AgentsDescription = GetDescription<Agent, string>(Agents);
I was wondering if it is possible to map multiple DTO objects to a single ViewModel object using Automapper?
Essentially, I have multiple DTO objects and would like to display information from each on a single screen in ASP.NET MVC 2.0. To do so I would like to flatten the DTO objects (or parts of them...) into the Viewmodel and pass said viewmodel to the view. If I had one DTO this would be easy, but I've never seen it being done with multiple. Obviously there are a number of roundabout ways to do this (outside of automapper), but this is the approach that I would like to take if possible.
Check for following link regarding your query
http://consultingblogs.emc.com/owainwragg/archive/2010/12/22/automapper-mapping-from-multiple-objects.aspx
You could create a composite DTO that holds two or more DTO objects and map the composite DTO to the output view model.
If you have 2 DTO classes and 1 flattened view model:
public class Dto1
{
public string Property1 { get; set; }
}
public class Dto2
{
public string Property2 { get; set; }
}
public class FlattenedViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
And you create mappings for both DTOs to view model:
CreateMap<Dto1, FlattenedViewModel>();
CreateMap<Dto2, FlattenedViewModel>();
You can map 1st DTO to the model and then just "append" 2nd DTO:
var dto1 = new Dto1 { Property1 = "Value1"; }
var dto2 = new Dto2 { Property2 = "Value2"; }
var model = Mapper.Map<FlattenedViewModel>(dto1); // map dto1 properties
Mapper.Map(dto2, model); // append dto2 properties
You can add a Map override extension method off IMappingEngine that takes a params array. Something like:
public static class AutoMapperExtensions
{
public static T Map<T>(this IMappingEngine engine, params object[] sources) where T : class
{
if (sources == null || sources.Length == 0)
return default(T);
var destinationType = typeof (T);
var result = engine.Map(sources[0], sources[0].GetType(), destinationType) as T;
for (int i = 1; i < sources.Length; i++)
{
engine.Map(sources[i], result, sources[i].GetType(), destinationType);
}
return result;
}
}
You could then call it like this:
var result = Mapper.Engine.Map<MyViewModel>(dto1, dto2, dto3);
This is the information from the expired link in this answer: https://stackoverflow.com/a/8923063/2005596
When using AutoMapper (http://automapper.codeplex.com ) I often have a scenario where I need to map several entities into one entity. Commonly this occurs when mapping from a number domain entities into a single view model (ASP.NET MVC). Unfortunately the AutoMapper API does not expose functionality to map several entities into one entity; however it is relatively simple to create some helper method to do this. Below I will illustrate the approach that I have taken.
In this example I have the following entities in my domain model
public class Person
{
public int Id { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
}
public class Address
{
public int Id { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Country { get; set; }
}
public class Comment
{
public string Text { get; set; }
public DateTime Created { get; set; }
}
In addition to this I have a requirement to render the person details the person’s address and any related comment on a single page (using ASP.NET MVC). To implement this I have created the view model shown below, which includes data from all three of the domain entities shown above
public class PersonViewModel
{
public int Id { get; set; }
[DisplayName("Firstname")]
public string Firstname { get; set; }
[DisplayName("Surname")]
public string Surname { get; set; }
[DisplayName("Address Line 1")]
public string AddressLine1 { get; set; }
[DisplayName("Address Line 2")]
public string AddressLine2 { get; set; }
[DisplayName("Country Of Residence")]
public string Country { get; set; }
[DisplayName("Admin Comment")]
public string Comment { get; set; }
}
In the controller action method I make three separate calls into the domain layer to retrieve the required entities but this still leaves the issue that I need to map several source entities onto a single destination entity. To perform this mapping I created a helper class which encapsulates AutoMapper and exposes functionality which enables the mapping of several source objects onto one destination object. This class is shown below
public static class EntityMapper
{
public static T Map<T>(params object[] sources) where T : class
{
if (!sources.Any())
{
return default(T);
}
var initialSource = sources[0];
var mappingResult = Map<T>(initialSource);
// Now map the remaining source objects
if (sources.Count() > 1)
{
Map(mappingResult, sources.Skip(1).ToArray());
}
return mappingResult;
}
private static void Map(object destination, params object[] sources)
{
if (!sources.Any())
{
return;
}
var destinationType = destination.GetType();
foreach (var source in sources)
{
var sourceType = source.GetType();
Mapper.Map(source, destination, sourceType, destinationType);
}
}
private static T Map<T>(object source) where T : class
{
var destinationType = typeof(T);
var sourceType = source.GetType();
var mappingResult = Mapper.Map(source, sourceType, destinationType);
return mappingResult as T;
}
}
To map several source objects onto one destination I have made use of the functionality provided by AutoMapper which allows you to perform a mapping between a source object and a destination object that already exists.
Finally below is the code from the controller that retrieves the three entities and performs the mapping onto a single view model
public ActionResult Index()
{
// Retrieve the person, address and comment entities and
// map them on to a person view model entity
var personId = 23;
var person = _personTasks.GetPerson(personId);
var address = _personTasks.GetAddress(personId);
var comment = _personTasks.GetComment(personId);
var personViewModel = EntityMapper.Map<PersonViewModel>(person, address, comment);
return this.View(personViewModel);
}
I just worked this out myself and have a great solution. It is most likely that your two views are actually related somehow in your system (especially if you are using Entity Framework). Check your models and you should see something which displays the relationship, if you don't then just add it. (The virtual)
Your models
public class Dto1
{
public int id { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
public string Property5 { get; set; }
public virtual Dto2 dto2{ get; set; }
}
public class Dto2
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
public string PropertyD { get; set; }
public string PropertyE { get; set; }
}
Your ViewModels
public class Dto1ViewModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public virtual Dto2VMForDto1 dto2{ get; set; }
}
//Special ViewModel just for sliding into the above
public class Dto2VMForDto1
{
public int id { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
Automapper looks like this:
cfg.CreateMap< Dto1, Dto1ViewModel>();
cfg.CreateMap< Dto2, Dto2VMForDto1 >();
I'm assuming you are getting your data with LinQ:
Dto1ViewModel thePageVM = (from entry in context.Dto1 where...).ProjectTo<Dto1ViewModel>();
Viola, everything will work. In your view just access by using model.dto2.PropertyB