The code generates all events of a specific producer, so that works.
But the problem is that when I return new ApiListModel< EventPerYearReport >() it goes to the class ApiListModel and then it says "status_code": 200, "data": null.
How do I generate, by executing the following URL: /api/dashboard/1, a value instead of "status_code": 200, "data": null?
DashboardController.cs
[HttpGet("{id}")]
public async Task<ApiListModel<EventPerYearReport>> GetEventPerYearReport(int id)
{
return await _dashboardService.GetEventPerYearReport(id);
}
DashboardService.cs
public async Task<ApiListModel<EventPerYearReport>> GetEventPerYearReport(int id)
{
var results = _dbContext.Events
.Where(p => p.ProducerId == id)
.GroupBy(e => e.DateStartEvent.ToString("yyyy"), (year, values) => new EventPerYear
{
year = year,
total = values.Count(),
}).ToList();
var report = new EventPerYearReport()
{
eventsPerYear = results
};
return new ApiListModel<EventPerYearReport>();
}
ApiListModel.cs
public class ApiListModel<T>
{
[JsonProperty(PropertyName = "status_code")]
public int StatusCode = 200;
[JsonProperty(PropertyName = "data")]
public List<T> Data;
}
EventPerYearReport.cs
public class EventPerYearReport
{
public List<EventPerYear> eventsPerYear { get; set; }
}
Your DashboardService.cs is returning new ApiListModel<EventPerYearReport>(); this will always have null data.
To fix this you need to use the following
public async Task<ApiListModel<EventPerYearReport>> GetEventPerYearReport(int id)
{
var results = _dbContext.Events
.Where(p => p.ProducerId == id)
.GroupBy(e => e.DateStartEvent.ToString("yyyy"), (year, values)
=> new EventPerYear
{
year = year,
total = values.Count(),
}).ToList();
return new ApiListModel<EventPerYearReport>()
{
Data = new EventPerYearRaport()
{
eventsPerYear = results
}
};
}
Related
While trying to Upsert a list # MongoDB i get the following error:
"Unable to determine the serialization information for o => o."
Order.cs *(removed properties for testing):
public class Order
{
[BsonId]
[BsonRepresentation(BsonType.String)]
public int Id { get; set; }
public string Number { get; set; }
}
Upsert:
public async Task SyncAsync(List<Order> orders)
{
var bulkUpdateModel = new List<WriteModel<Order>>();
foreach (var order in orders)
{
var filter = Builders<Order>.Filter.Eq(o => o.Id, order.Id);
var updateDefinition = Builders<Order>.Update.Set(o => o, order);
var upsertOne = new UpdateOneModel<Order>(filter, updateDefinition) { IsUpsert = true };
bulkUpdateModel.Add(upsertOne);
}
await _orders.BulkWriteAsync(bulkUpdateModel);
}
You could try the ReplaceOneModel instead:
var upsertOne = new ReplaceOneModel<Order>(filter, order)
{
IsUpsert = true
};
Solution
I found out that you can't update a whole document, only certain properties you set in the updateDefinition...
Not working:
var updateDefinition = Builders<Order>.Update.Set(o => o, order);
Working:
var updateDefinition = Builders<Order>.Update.Set(o => o.Whatever, order.Whatever);
I don't want to use reflection, so switched to Replace where it's possible to update the whole document.
Example
public async Task SyncAsync(List<Order> orders)
{
var bulkUpdateModel = new List<WriteModel<Order>>();
foreach (var order in orders)
{
var filter = Builders<Order>.Filter.Eq(o => o, order);
var writeModel = new ReplaceOneModel<Order>(filter, order) { IsUpsert = true };
bulkUpdateModel.Add(writeModel);
}
await _orders.BulkWriteAsync(bulkUpdateModel);
}
I'm a beginner. I try to get all the positions of the employee, but only the position of the first employee is returned. Employees and positions relationship is many-to-many. Whatever you do, the result is the same :(
View Model
public class DivisionEmployeeViewModel
{
public DivisionEmployee DivisionEmployees { get; set; }
public Division Division { get; set; }
public IEnumerable<DivisionEmployee> DivisionEmployeeList { get; set; }
public IEnumerable<EmployeePosition> EmployeePositionList { get; set; } // get 1 obj
public IEnumerable<SelectListItem> DivisionEmployeeListDropDown { get; set; }
}
Action Details
[HttpGet]
public async Task<IActionResult> Details(int id)
{
var model = new DivisionEmployeeViewModel
{
DivisionEmployeeList = await _db.DivisionEmployeesModel.Include(x => x.Employee)
.Include(x => x.Division).Where(x => x.Division_Id == id).ToListAsync(),
// Get only 1 obj
EmployeePositionList = await _db.EmployeePositions.Include(x => x.Position)
.Include(x => x.Employee).Where(x => x.Employee_Id == id).ToListAsync(),
//
DivisionEmployees = new DivisionEmployee()
{
Division_Id = id
},
Division = await _db.Divisions.FirstOrDefaultAsync(x => x.Id == id)
};
List<int> tempAssignedList = model.DivisionEmployeeList.Select(x => x.Employee_Id).ToList();
List<int> tempAssignedList2 = model.EmployeePositionList.Select(x => x.Position_Id).ToList(); // ? Get only 1 obj
// Get all items who's Id isn't in tempAuthorsAssignedList and tempCitiesAssignedList
var tempList = await _db.Employees.Where(x => !tempAssignedList.Contains(x.Id)).Where(x => !tempAssignedList2.Contains(x.Id)).ToListAsync();
model.DivisionEmployeeListDropDown = tempList.Select(x => new SelectListItem
{
Text = x.FullName,
Value = x.Id.ToString()
});
return View(model);
}
Project GitHub https://github.com/ValencyJacob/DepartmentManagementApp-Many-to-Many
Your Division_Id and Employee_Id are both id in Details(int id)?And tempAssignedList2 is a list of positionId,why you use .Where(x => !tempAssignedList2.Contains(x.Id)) to compare employeeId with positionId? – Yiyi You
how to retrieve partial object?
{
Id:123,
Name:"david",
Languages:[{b:"en"},{b:"ru"}]
}
public async Task<myObj> Get(long id, string lang=null)
{
FilterDefinition<myObj> filter = Builders<myObj>.Filter.Eq(s => s.Id, id)
& Builders<myObj>.Filter.ElemMatch(l => l.Languages, s => s.b== lang);
ProjectionDefinition<myObj> projection = Builders<Symptom>.Projection
.Include(d => d.Id)
.Include(d => d.Name)
.Include(d => d.Languages[-1]);
FindOptions<myObj> options = new FindOptions<myObj> { Projection = projection };
using (IAsyncCursor<myObj> cursor = await db.Collection.FindAsync(filter, options))
{
return cursor.SingleOrDefault();
}
}
if i call function get(123,"cn") i expect to get:
{
Id:123,
Name:"david",
Languages:null
}
instead of null.
how to fix the query to achieve my demand?
i think this will get the job done:
public async Task<myObj> Get(long id, string lang = null)
{
var res = await db.Collection.AsQueryable()
.Where(m =>
m.Id == id &&
m.Languages.Any(l => l.b == lang))
.SingleOrDefaultAsync();
return res ?? new myObj { _Id = id, Languages = null };
}
If you want to display the languages only when they match (and null if none match up), then try the following
public async Task<myObj> Get(long id, string lang = null)
{
FilterDefinition<myObj> filter = Builders<myObj>.Filter.Eq(s => s.Id, id)
var result = await collection.Find(filter).SingleOrDefaultAsync();
if (result != null)
result.Languages = result.Languages?.Where(lng => lng.b.Equals(lang)).ToList();
return result;
}
You will get your object that you want based on the ID.. then further it will return only those languages that match up with language that you are passing (null or otherwise).
It's working. I don't know what you mean by "instead of null".
One minor thing, that you would like to not include Languges, instead you projected the Languages to an array range with the [-1]. So it's just return last element of the array. The final code is:
> db.ItemWithLanguages.find()
{ "_id" : ObjectId("5dfb57c9692d22eefa6e0cfe"), "Id" : 123, "Name" : "david", "Languages" : [ { "B" : "en" }, { "B" : "cn" } ] }
internal class MyObj
{
public long Id { get; set; }
[BsonId]
[BsonElement("_id")]
public ObjectId MyId { get; set; }
public string Name { get; set; }
public List<Language> Languages { get; set; }
}
internal class Language
{
public string B { get; set; }
}
public static async Task<MyObj> Get(IMongoCollection<MyObj> collection, long id, string lang = null)
{
FilterDefinition<MyObj> filter = Builders<MyObj>.Filter.Eq(s => s.Id, id)
& Builders<MyObj>.Filter.ElemMatch(l => l.Languages, s => s.B == lang);
// excluding d.Languages by not including it.
// it makes Languages = null.
ProjectionDefinition<MyObj> projection = Builders<MyObj>.Projection
.Include(d => d.Id)
.Include(d => d.Name);
FindOptions<MyObj> options = new FindOptions<MyObj> { Projection = projection };
using (IAsyncCursor<MyObj> cursor = await collection.FindAsync(filter, options))
{
return cursor.SingleOrDefault();
}
}
...
string connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
var db = client.GetDatabase("test");
var myObjs = db.GetCollection<MyObj>("ItemWithLanguages");
MyObj ret;
Task.Run(async () => { ret = await Get(myObjs, 123, "cn"); }).ConfigureAwait(false).GetAwaiter()
.GetResult();
Using .Net Nore C# MVC
I have the following code:
My data:
public IEnumerable<string> GetData(string id)
{
return _context.TableData
.Where(r => r.ID == id)
.Select (r => r.Name).ToList();
}
My MVC controller:
public IActionResult GetDDL(string id)
{
var result = _repo.GetData(id);
//Above gives me
//[0] = "United States"
//[1] = "United Kingdom"
var json = JsonConvert.SerializeObject(result);
//Above json convert gives me ["United States","United Kingdom"]
return Json(json);
}
Above code does return me Json but I wanted to know how can I create new JSON such that it return me as below:
[{"Text":"United States","Text":"United Kingdom"}]
Basically, I want to bind this back to my dropdown which expects the "Text" property with the JSON array.
1. In the controller
public IActionResult GetDDL(string id)
{
var result = _repo.GetData(id);
var withProp = result.Select(x => new { Text = x });
var json = JsonConvert.SerializeObject(withProp);
return Json(json);
//Or shorter:
var result = _repo.GetData(id).Select(x => new { Text = x });
var json = JsonConvert.SerializeObject(result);
return Json(json);
}
2. In the repository
You cannot return an anonymous type so you should create a class that'll hold the data and use that to return from the repository:
public class Data
{
public string Text { get; set; }
}
public IEnumerable<Data> GetData(string id)
{
return _context.TableData
.Where(r => r.ID == id)
.Select (r => new Data { Text = r.Name });
}
Usage in the controller remains unchanged then:
public IActionResult GetDDL(string id)
{
var result = _repo.GetData(id);
var json = JsonConvert.SerializeObject(result);
return Json(json);
}
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.