I have a HttpResponseMessage method that returns a JSON based on DB data:
public HttpResponseMessage RespMsg(JObject jsonData)
{
HttpResponseMessage response = new HttpResponseMessage();
dynamic json = jsonData;
int recId = jsonData.Id;
var respStructure = myTable.Where(r => r.Id==recId).Select(t => new
{
t.Id,
t.Name
}
var responseJson = JsonConvert.SerializeObject(respStructure);
response.Content = new StringContent(responseJson, null, "application/json");
return response;
}
The response I get is something like {"Id":3,"Name":Third}.
The row in T1, has multiple rows in table T2
var t2Resp = T2.Where(c => c.T1Id == recId);
foreach (var t in t2Resp) {
//call a method that return an object with computed data
}
Is there a way to add the data from foreach as separate JSON like {"Id":3,"Name":"Third"} {first data from foreach} {second data from foreach}? The first one is from T1 query and the next ones depending on t2Resp length
Hint:- First You have to create a DTO object that matches with your response. Since T1 and T2 have one-to-many relationship create a DTO class with below structure.
public class DtoData
{
public string id { get; set; }
public string Name { get; set; }
public List<DaatFromT2> T2Data { get; set; }
}
public class DaatFromT2
{
public string prop1 { get; set; }
public int prop2 { get; set; }
public DateOnly prop3 { get; set; }
}
Then you have to use this class to populate data from T1 and T2 and finally sterilize to JSON. Something as shown below .
var resposeStructure = new List<DtoData>();
var t1data = myTable.Where(r => r.Id==recId).Select(t => new
{
t.Id,
t.Name
};
var t2Resp = T2.Where(c => c.T2Id == recId);
foreach (var t in t1data)
{
var data = new DtoData
{
id = t.Id,
Name = t.Name,
T2Data = t2Resp.Where(c => t.id == t2Resp.someid)
.Select(t => new
{
//call a method that return an object with computed data
//and map to corresponding properties
});
}
resposeStructure.Append(data);
}
var responseJson = JsonConvert.SerializeObject(respStructure);
May be theses code snippets give you some idea and able to sort this issue.
Happy coding :)
Related
Initially I was using automapper for this but its seems way harder for me to implement it.
Basically, I just want to return an empty list instead of null values. I can do this on projects level but not on teammates level. The API must not return a null because the UI that consumes it will have an error.
Sample of my implementation below:
Projects = !Util.IsNullOrEmpty(x.Projects) ? x.Projects : new List<ProjectsDto>(),
Ill highly appreciate if someone can guide me on how to manually map this with null/empty checking.
If you can also provide and example using automapper that too will be very helpful.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<ProjectsDto> Projects { get; set; }
}
public class ProjectsDto
{
public string Status { get; set; }
public List<TeammatesDto> Teammates { get; set; }
}
public class TeammatesDto
{
public string TeammateName { get; set; }
public string PreviousProject { get; set; }
}
//Get by Id
var employee = await _context.Employees
.Where(x => x.id.Equals(request.Id)
.FirstOrDefaultAsync(cancellationToken);
//Map employee
EmployeeDto ret = new EmployeeDto()
{
Id = employee.id,
Name = employee.Name,
Projects = null //TODO: map manually
}
//Get all employees
var employees = await _context.Employees.AsNoTracking()
.ToListAsync(cancellationToken);
//Map here
IList<EmployeeDto> list = new List<EmployeeDto>();
foreach (var x in employees)
{
EmployeeDto dto = new EmployeeDto()
{
Id = x.id,
Name = x.Name,
Projects = null //TODO: map manually
};
list.Add(dto);
}
return list;
Instead of materializing full entities, do the following:
var query = _context.Employees
.Select(e = new EmployeeDto
{
Id = e.id,
Name = e.Name,
Projects = e.Projects.Select(p => new ProjectDto
{
Status = p.Status,
Templates = p.Templates.Select(t => new TemplateDto
{
TeammateName = t.TeammateName,
PreviousProject = t.PreviousProject
}).ToList()
}).ToList()
}
);
var result = await query.ToListAsync();
How can I return fieldList from an IQueryable object?
// fieldList="Code,Name";
var result = from Activity in query
select new
{
Code = Activity.Code,
Name = Activity.Name,
StatusCode = Activity.ClaimStatus.Name
};
DTO
public class CustomDto
{
public string Code { get; set; }
public string Name { get; set; }
public string StatusCode { get; set; }
}
Convert To Dto
var result = items.AsQueryable().Select(x => new CustomDto()
{
Code = x.Code,
Name = x.Name,
StatusCode = x.ClaimStatus
}).ToList();
I have the following method to return the data of two entities.
public List<Object> GetDados()
{
var sendFilter = new Filter<MessageSent>();
//employeeFilter.Add(x => x.Name, name);
sendFilter.Add(x => x.MessageSentSeq, ID_GROUP_SEND);
// You can add more filters
MessageSentService svc = new MessageSentService();
var messages = svc.Find(sendFilter).ToList();
var employees = new EmployeeService().GetAll();
var query =
from employee in employees
join message in messages
on employee.EmployeeId equals message.EmployeeId
select new
{
MessageSentId = message.MessageSentId,
//EmployeeId = message.EmployeeId,
//MessageSentSeq = message.MessageSentSeq,
Name = employee.Name,
Surname = employee.Surname,
Mobile = employee.Mobile,
Email = employee.Email,
Status = "N"
};
return query.ToList<Object>();
}
Call
ILog log = LogManager.GetLogger(typeof(Form));
List<Object> Send;
Send = GetDados();
gvSent.DataSource = Send;
When doing send I would like to update the record that is inside object var query that in turn populates my grid
I need to set the status field with S at the end of everything I updated my database with the items that were sent correctly.
Because your function returns a List<Object>, you'll be unable to modify those properties without using Reflection or some other drastic measure. If you plan on this data being modifiable, you'll need to make sure the data you're returning is typed. First define a simple class:
class Dado
{
public string MessageSentId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public bool Mobile { get; set; }
public string Email { get; set; }
public string Status { get; set; }
}
...then modify your function to return instances of this type:
public List<Dado> GetDados()
{
var sendFilter = new Filter<MessageSent>();
//employeeFilter.Add(x => x.Name, name);
sendFilter.Add(x => x.MessageSentSeq, ID_GROUP_SEND);
// You can add more filters
MessageSentService svc = new MessageSentService();
var messages = svc.Find(sendFilter).ToList();
var employees = new EmployeeService().GetAll();
return (
from employee in employees
join message in messages
on employee.EmployeeId equals message.EmployeeId
select new Dado
{
MessageSentId = message.MessageSentId,
//EmployeeId = message.EmployeeId,
//MessageSentSeq = message.MessageSentSeq,
Name = employee.Name,
Surname = employee.Surname,
Mobile = employee.Mobile,
Email = employee.Email,
Status = "N"
}
).ToList();
}
Now, in your code after populating the grid can do something like:
foreach (var dado in Send) {
dado.Status = "S";
}
I am working on code which will give Cartesian product of two anonymous types. These 2 anonymous types are generated from database.
Code for 1st anonymous type:
private IEnumerable<object> GetItem()
{
return _unitOfWork.GetRepository<Item>()
.ListAll()
.Select(x => new
{
itemId = x.Id,
itemName = x.Name
})
}
Code for 2nd anonymous type:
private IEnumerable<object> GetVenue()
{
return _unitOfWork.GetRepository<Venue>()
.ListAll()
.Select(x => new
{
locationName = x.Address.City,
venueId = x.VenueId,
venueName = x.Name
})
}
I have following method to get the data and perform Cartesian product and return the data.
public object GetRestrictLookupInfo(IEnumerable<int> lookupCombinations)
{
IEnumerable<object> restrictList = new List<object>();
if (lookupCombinations.Contains(1))
{
var tempProductProfileList = GetItem();
restrictList = tempProductProfileList.AsEnumerable();
}
if (lookupCombinations.Contains(2))
{
var tempProductGroupList = GetVenue();
restrictList = (from a in restrictList.AsEnumerable()
from b in tempProductGroupList.AsEnumerable()
select new { a, b });
}
return restrictList;
}
I have controller which calls this method and return data in json format.
Controller Code
public HttpResponseMessage GetData(IEnumerable<int> lookupCombinations)
{
var lookupRestrictInfo = _sellerService.GetRestrictLookupInfo(lookupCombinations);
return Request.CreateResponse(HttpStatusCode.OK, lookupRestrictInfo);
}
Response expected is:-
[ {
"itemId": 1,
"itemName": "Music",
"locationName": "Paris",
"venueId": 99,
"venueName": "Royal Festival Hall"
} ]
Response which I receive is
[ {
"a": {
"itemId": 1,
"itemName": "Music"
},
"b": {
"locationName": "Paris",
"venueId": 99,
"venueName": "Royal Festival Hall" } }]
I am not able to get the expected JSON string.
You should start with the simplest possible code that shows your problem; your code above has a lot of complexities that may (or may not) have anything to do with your problem. Is this about manipulating anonymous types? Doing a Cartesian product with LINQ? Converting an object to JSON?
Here's one possible answer to what you might be looking for; notice that you can pass around anonymous types using generics instead of object.
namespace AnonymousTypes
{
class Program
{
static string Serialize(object o)
{
var d = (dynamic)o;
return d.ItemId.ToString() + d.ItemName + d.VenueId.ToString() + d.LocationName + d.VenueName;
}
static string GetData<T>(IEnumerable<T> result)
{
var retval = new StringBuilder();
foreach (var r in result)
retval.Append(Serialize(r));
return retval.ToString();
}
static string GetRestrictLookupInfo()
{
var restrictList = new[] { new { Id = 1, Name = "Music" }, new { Id = 2, Name = "TV" } };
var tempProductGroupList = new[] { new { LocationName = "Paris", Id = 99, Name = "Royal Festival Hall" } };
var result = from item in restrictList
from venue in tempProductGroupList
select new
{
ItemId = item.Id,
ItemName = item.Name,
LocationName = venue.LocationName,
VenueId = venue.Id,
VenueName = venue.Name
};
return GetData(result);
}
public static string GetData()
{
return GetRestrictLookupInfo();
}
static void Main(string[] args)
{
var result = GetData();
}
}
}
If that's not what you're looking for, you might start with code that doesn't use anonymous types, such as
namespace AnonymousTypes
{
sealed class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
sealed class Venue
{
public string LocationName { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
sealed class ItemAndVenue
{
public int ItemId { get; set; }
public string ItemName { get; set; }
public string LocationName { get; set; }
public int VenueId { get; set; }
public string VenueName { get; set; }
}
class Program
{
static IEnumerable<Item> GetItem()
{
return new[] { new Item { Id = 1, Name = "Music" } };
}
static IEnumerable<Venue> GetVenue()
{
return new[] { new Venue { LocationName = "Paris", Id = 99, Name = "Royal Festival Hall" } };
}
static IEnumerable<ItemAndVenue> GetRestrictLookupInfo()
{
var restrictList = GetItem();
var tempProductGroupList = GetVenue();
var result = from item in restrictList
from venue in tempProductGroupList
select new ItemAndVenue
{
ItemId = item.Id,
ItemName = item.Name,
LocationName = venue.LocationName,
VenueId = venue.Id,
VenueName = venue.Name
};
return result;
}
static string GetData()
{
var v = GetRestrictLookupInfo().First();
return v.ItemId.ToString() + v.ItemName + v.VenueId.ToString() + v.LocationName + v.VenueName;
}
static void Main(string[] args)
{
var result = GetData();
}
}
}
In order to produce a single item in the output you need to create a new type, named or anonymous. Since you are using objects rather than actual types, the quickest approach is to cast them to dynamic:
var tempProductGroupList = GetVenue();
restrictList = (from a in restrictList.Cast<dynamic>()
from b in tempProductGroupList.Cast<dynamic>()
select new {
itemId = (int)a.itemId,
itemName = (string)a.itemName,
locationName = (string)b.locationName,
venueId = (int)b.venueId,
venueName = (string)b.venueName
});
This code is tightly coupled to the code producing both lists, because it assumes the knowledge of the field names of types passed into it dynamically. Any change in the structure of source data must be followed by a change in the code making combinations. In addition, it defeats run-time checking, so you need to be very careful with this code.
Try to create a simple object instead of nesting:
select new { a.itemId, a.itemName, b.locationName }
Like an option:
public object GetRestrictLookupInfo(IEnumerable<int> lookupCombinations)
{
List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
if (lookupCombinations.Contains(1))
{
var tmp = _unitOfWork.GetRepository<Item>()
.ListAll()
.Select(x => new
{
itemId = x.Id,
itemName = x.Name
})
.Select(x =>
{
var dic = new Dictionary<string, object>();
dic.Add(nameof(x.itemId), x.itemId);
dic.Add(nameof(x.itemName), x.itemName);
return dic;
});
result.AddRange(tmp);
}
if (lookupCombinations.Contains(2))
{
var tmp = _unitOfWork.GetRepository<Venue>()
.ListAll()
.Select(x => new
{
locationName = x.Address.City,
venueId = x.VenueId,
venueName = x.Name
})
.Select(x =>
{
var dic = new Dictionary<string, object>();
dic.Add(nameof(x.locationName), x.locationName);
dic.Add(nameof(x.venueId), x.venueId);
dic.Add(nameof(x.venueName), x.venueName);
return dic;
});
result = result.SelectMany(r => tmp.Select(t => r.Concat(t)));
}
return result;
}
It looks like some magic. I uses dictionary instead of object. It can be make in more clear way (extract few methods), but the idea should be clear.
Then, during serialization it will be presented as you need.
I have two DTOs:
public class MasterDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<DetailDTO> Details { get; set; }
}
public class DetailDTO
{
public int Id { get; set; }
public string DetailName { get; set; }
}
Also, I have a function:
using (var context = new Context())
{
var r = context.MasterData
.Select(d => new MasterDTO
{
Id = d.Id,
Name = d.Name,
}
}
I need to fill the list of DetailDTOs too and do it in a single request.
At this moment, I have to get list of DetailsData data and add it through foreach to the MasterDTO, which, of course causes a lot of requests to the database server.
Is there a better solution?
In your data call, do an eager load on your DetailData.
Example:
var r = context.MasterData.Include("DetailData")
DetailData should be the name of your navigation property attached to your MasterData entity.
This will cause detail data to be pulled along with your call for MasterData.
The full call may look something like this:
using (var context = new Context())
{
context.LazyLoadingEnabled = false;
var r = context.MasterData.Include("DetailData")
.Select(d => new MasterDTO()
{
Id = d.Id,
Name = d.Name,
Details = d.Details.Select(dt => new DetailDTO()
{
Id = dt.Id,
DetailName = dt.DetailName
})
});
}