Dart - GroupBy with nested lists - list

Could use a Dart hero. Kinda new so let me try to explain short but correctly
I have the following object structure
Client has a List<Project>
Project has a List<Registration>
Registration has a field date which is of type DateTime
class Client {
String id;
String name;
String hexColor;
List<Project> projects;
}
class Project {
String id;
String name;
List<Registration> registrations;
}
class Registration {
String id;
String description;
DateTime date;
int minutesWorked;
}
So currently I have a List<Client> but I want to do a GroupBy based on the Registration.date value... how to do a groupBy with a nested list?
Expected output:
[
2020-01-01 00:00:00.000: [Instance of Client, Instance of Client, Instance of Client],
2020-01-02 00:00:00.000: [Instance of Client]
]
how on earth should this be pulled off!

How about:
Map<DateTime, List<Client>> clientsByRegsitrationDate(Iterable<Client> clients) {
var result = <DateTime, List<Client>>{};
for (var client in clients) {
for (var registration in client.registrations) {
result.putIfAbsent(registration.date, () => []).add(client);
}
}
return result;
}
This assumes that all registration dates for the same client are different, otherwise the same client can end up in a list more than once.
If you want to avoid that, maybe:
Map<DateTime, List<Client>> clientsByRegsitrationDate(Iterable<Client> clients) {
var result = <DateTime, List<Client>>{};
for (var client in clients) {
for (var registration in client.registrations) {
var list = result.putIfAbsent(registration.date, () => []);
if (list.isEmpty || !identical(list.last, client)) list.add(client);
}
}
return result;
}
Or just use sets instead of lists to collect the clients:
Map<DateTime, Set<Client>> clientsByRegsitrationDate(Iterable<Client> clients) {
var result = <DateTime, List<Client>>{};
for (var client in clients) {
for (var registration in client.registrations) {
result.putIfAbsent(registration.date, () => {}).add(client);
}
}
return result;
}
That also avoids double-counting clients if they occur more than once in clients.

Related

insert whole list of data into sql database table in xamarin.android

i'm trying to create an application where data in a list must be inserted into a database table at once. I made some research and found out that this is possible using user-defined table types where in c# a datatable is used and passed to a stored procedure that is executed. now my problem is that there are no data tables in Xamarin.Android. so I thought to use a list instead. my idea was to create a list in the application and pass it to the webservice method, and in my webservice method I receive the list and convert it to a datatable then pass it as a parameter to the stored procedure. I wrote the following codes:
in my webservice:
[WebMethod]
public bool insrt_dt(List<Class1> lst)
{
SqlParameter param;
SqlConnection conn = new SqlConnection(new DBConnection().ConnectionString);
DataTable dt = list_to_dt(lst);
SqlCommand cmd = new SqlCommand("Insert_Customers", conn);
cmd.CommandType = CommandType.StoredProcedure;
if (conn.State == System.Data.ConnectionState.Closed)
{
conn.Open();
}
param = new SqlParameter("#tblcustomers", dt);
param.Direction = ParameterDirection.Input;
param.DbType = DbType.String;
cmd.Parameters.Add(param);
cmd.CommandTimeout = 300;
int a=cmd.ExecuteNonQuery();
if (a > 0)
{
return true;
}
else return false;
}
}
Class1:
public class Class1
{
public int id { get; set; }
public string name { get; set; }
public string country { get; set; }
}
in my Xamarin.Android app
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
Button btn = FindViewById<Button>(Resource.Id.button1);
btn.Click += delegate
{
wr.WebService1 ws = new wr.WebService1();
wr.Class1 class1 = new wr.Class1();
List<wr.Class1> lst = new List<wr.Class1>(){
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
ws.insrt_dt(lst);
ws.insrt_dtCompleted += Ws_insrt_dtCompleted;
};
}
private void Ws_insrt_dtCompleted(object sender, wr.insrt_dtCompletedEventArgs e)
{
bool l = e.Result;
if (l == true)
Toast.MakeText(this, "khh", ToastLength.Long).Show();
else
Toast.MakeText(this, "ijo'pioo", ToastLength.Long).Show();
}
}
but I keep getting this error:
Argument 1: cannot convert from 'System.Collections.Generic.List<app_dt.wr.Class1>' to 'app_dt.wr.Class1[]
so I used these lines instead
new wr.Class1() { id = 1, name = "hgf", country = "khg" },
new wr.Class1() { id = 2, name = "hgf", country = "khg"} };
wr.Class1[] class1s = lst.ToArray();
ws.insrt_dt(class1s);
now I don't get an error, but it doesn't work, I mean why does it say that the webservice method input must be an array and I've created it as a list. any suggestions for this?
As i know, Xamarin do not support System.Data.SqlClient. If you want to use the database for the Xamarin android project, you could use the SQLite.NET.
Install the package from the NuGet.
NuGet: sqlite-net-pcl https://www.nuget.org/packages/sqlite-net-pcl/
For the code sample about how to use the database in Xamarin, you could check the link below. https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows
For Xamarin.Android, you could check the sample code in the link below. https://learn.microsoft.com/en-us/xamarin/android/data-cloud/data-access/using-sqlite-orm

How to unit test a repository and mock db with moq

I am onboarding alone on an existing project that do not have any unit test. My first goal before any refactoring is to cover 100% of the code. I would like to avoid any regression.
I have read how do I mock sqlconnection or should I refactor the code? but my case as you can see below is quite different cause I need to do more than stub simply the sqlConnection. Basically, I need to mock the db. I would like to know the best approach to achieve it.
(By the way, I do not want to use any ORM such as Entity).
Below the code of the repository :
public class HotelRepository : IHotelRepository
{
private readonly IDbConnection _dbConnection;
private readonly ILogService _loggerService;
public HotelRepository(IDbConnection dbConnection, ILogService loggerService)
{
_dbConnection = dbConnection;
_loggerService = loggerService;
}
public HotelDo GetByRid(string rid)
{
return Find(rid).FirstOrDefault();
}
public List<HotelDo> Find(string text)
{
try
{
_dbConnection.Open();
var items = new List<HotelDo>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelSearchByRidOrName";
command.Parameters.Add(new SqlParameter("#Text", text));
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
items.Add(new HotelDo()
{
Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
IsOnline = SqlExtension.ReaderToBoolConverter(reader["IsOnline"]) ?? false,
CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"])
});
}
}
}
return items;
}
catch (Exception e)
{
var errorMessage = $"HotelRepository Find, text {text} ";
_loggerService.Trace(LogSeverity.Error, errorMessage, e);
throw new DalException() { Source = errorMessage, };
}
finally
{
_dbConnection.Close();
}
}
public List<HotelDo> GetAll()
{
try
{
_dbConnection.Open();
var items = new List<HotelDo>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelGetAll";
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
bool.TryParse(reader["IsOnline"].ToString(), out var isOnline);
items.Add(new HotelDo()
{
Id = SqlExtension.ReaderToIntConverter(reader["Id"]),
Rid = SqlExtension.ReaderToStringConverter(reader["RIDHotel"]),
Name = SqlExtension.ReaderToStringConverter(reader["Name"]),
CodeCountry = SqlExtension.ReaderToStringConverter(reader["CodeCountry"]),
LinkPms = SqlExtension.ReaderToStringConverter(reader["LinkPms"]),
IdPms = SqlExtension.ReaderToNullableIntConverter(reader["IdPms"]),
IdBrand = SqlExtension.ReaderToNullableIntConverter(reader["IdBrand"]) ?? 0,
LinkResaWeb = SqlExtension.ReaderToStringConverter(reader["LinkResaWeb"]),
IsOnline = isOnline
});
}
}
}
return items;
}
catch (Exception e)
{
var errorMessage = $"HotelRepository GetAllHotels";
_loggerService.Trace(LogSeverity.Error, errorMessage, e);
throw new DalException() { Source = errorMessage, };
}
finally
{
_dbConnection.Close();
}
}
}
Thank you for your help
So based on what you've got I've set up a test frame for you to follow. I've removed less important components for breviety.
Before you you jump in I just want to give my 2 cents, if you don't know how to do this sort of thing you seem to be more or less in a junior position or less experiance with C# and also found your self in a more or less mature company that doesn't care about the development deparment, since an uncovered project just get's thrown your way says you don't have alot of resources to go about to imrpove the code base.
Test only the things that have business value (can you put a price on the piece of logic if it brakes)
Delivering stuff faster will make you look better as a programmer (noone in the business gives a damn about test covarage)
Study hard, get your experiance, good reputation and don't be afraid to get the hell out of there as soon as you start getting bored.
Main
void Main()
{
var idIndex = 0;
var ids = new string[] { "1", "2" };
var mockDataReader = new Mock<IDataReader>();
mockDataReader.SetupSequence(x => x.Read()).Returns(true).Returns(true).Returns(false);
mockDataReader.SetupGet(x => x["Id"]).Returns(() => ids[idIndex]).Callback(() => idIndex++);
var mockParameters = new Mock<IDataParameterCollection>();
var mockCommand = new Mock<IDbCommand>();
mockCommand.SetupGet(x => x.Parameters).Returns(mockParameters.Object);
mockCommand.Setup(x => x.ExecuteReader(CommandBehavior.CloseConnection)).Returns(mockDataReader.Object);
var mockConnection = new Mock<IDbConnection>();
mockConnection.Setup(x => x.CreateCommand()).Returns(mockCommand.Object);
var repo = new HotelRepository(mockConnection.Object);
var result = repo.Find("search");
Assert.Equal("1", result[0].Id);
Assert.Equal("2", result[1].Id);
}
Repository
public class HotelRepository
{
private readonly IDbConnection _dbConnection;
public HotelRepository(IDbConnection dbConnection)
{
_dbConnection = dbConnection;
}
public List<Pony> Find(string text)
{
_dbConnection.Open();
var items = new List<Pony>();
using (var command = _dbConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "dbo.HotelSearchByRidOrName";
command.Parameters.Add(new SqlParameter("#Text", text));
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
while (reader.Read())
{
items.Add(new Pony
{
Id = reader["Id"].ToString()
});
}
}
}
return items;
}
}
Just a dumb o'l pony
public class Pony {
public string Id { get; set; }
}

How can I distinct a complex object list in DART

I have one list of complex object. How can I distinct the list using their IDs?
I cant use toSet and similars, because the hashcode from the objects all are diferent.
1) Vanilla Dart
Loop through the list, adding IDs to a set as you go. Whenever you add an ID to the set that didn't already exist, add that element to a new list of distinct values.
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var idSet = <String>{};
var distinct = <Data>[];
for (var d in list) {
if (idSet.add(d.id)) {
distinct.add(d);
}
}
}
class Data {
Data(this.id);
final String id;
}
2) Packages
Several packages exist that expand on default the Iterable utility methods, such as flinq or darq. They add a distinct method you can call to easily get a list of unique members of a list based on some property of the members.
import 'package:darq/darq.dart';
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var distinct = list.distinct((d) => d.id).toList();
}
(Disclaimer, I am the maintainer of darq.)
Try to use this extension:
extension IterableExtension<T> on Iterable<T> {
Iterable<T> distinctBy(Object getCompareValue(T e)) {
var result = <T>[];
this.forEach((element) {
if (!result.any((x) => getCompareValue(x) == getCompareValue(element)))
result.add(element);
});
return result;
}
}
Using:
var distinctList = someList.distinctBy((x) => x.oid);
Or you can use a hash there.

Api Response as a List / fetching all the data from api response

I am new to .netcore mvc architecture. I am trying to consume the api data response, So far I have successfully fetched the data, but the problem I am facing is when the api response/result is more than one. Forexample if the actuall api response is the following
"responseHeader":{
"status":0,
"QTime":0,
"params":{
"q":"title:\"A\""}},
"response":{"numFound":3,"start":0,"docs":[
{
"date":"1970-01-01T00:00:00Z",
"tstamp":"2019-11-22T12:22:31.698Z",
"digest":"e23d679991d80d832504e7395d139fe4",
"contentLength":"25476",
"boost":0.0,
"title":["emb- A1]
"url":"https://www.example.com/a/b/c0/"},
{
"date":"1970-01-01T00:00:00Z",
"tstamp":"2019-11-22T12:22:31.698Z",
"digest":"e23d679991d80d832504e7395d139fe4",
"contentLength":"25476",
"boost":0.0,
"title":["emb - A2]
"url":"https://www.example.com/a/b/c1/"
},
{
"date":"1970-01-01T00:00:00Z",
"tstamp":"2019-11-22T12:22:31.698Z",
"digest":"e23d679991d80d832504e7395d139fe4",
"contentLength":"25476",
"boost":0.0,
"title":["emb - A3]
"url":"https://www.example.com/a/b/c2/"
}
I am only getting
{"title":"[\r\n \"emb- A1","source":"https://www.example.com/a/b/c0/"}
instead of having all the response data.
My Code is below.
Model
SearchModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace searchEngineTesting.Models
{
public class SearchModel
{
public string Title;
public string Source;
}
}
Controller
EngineController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using searchEngineTesting.Models;
namespace searchEngineTesting.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EngineController : ControllerBase {
[HttpGet("[action]/{query}")]
public async Task<IActionResult> Product(string query)
{
var model = new SearchModel();
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://xx.xx.xxx.xx:8080");
var response = await client.GetAsync($"/abc/xxx/select?q=title%3A%22{query}%22");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync();
var root = (JObject)JsonConvert.DeserializeObject(stringResult);
//var details = JsonConvert.DeserializeObject<SearchModel>(stringResult);
var items = root.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var item in items)
{
if (item.Key == "response")
{
var key = item.Value.SelectToken("").OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var k in key)
{
if(k.Key == "docs")
{
var tests = JsonConvert.DeserializeObject<JArray>(k.Value.ToString());
var data = k.Value.SelectToken("").Children().First();
var test = data.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value).ToList();
foreach (var t in test)
{
if (t.Key =="url")
{
model.Source = t.Value.ToString();
}
else if (t.Key == "title")
{
model.Title = t.Value.ToString(); }
}
}
}
}
}
return new JsonResult(model);
}
catch (InvalidOperationException httpreq) {
return BadRequest("Sorry: There are no results for your query");
}
}
}
}
}
How can I retrieve whole of the response I am getting from actual API.
Please help..!
How can I retrieve whole of the response I am getting from actual API.
If you want to return all the actual api response,then just use below code:
[HttpGet("[action]/{query}")]
public async Task<IActionResult> Product(string query)
{
var model = new SearchModel();
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://xx.xx.xxx.xx:8080");
var response = await client.GetAsync($"/abc/xxx/select?q=title%3A%22{query}%22");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync();
var root = (JObject)JsonConvert.DeserializeObject(stringResult);
return new JsonResult(root);
}
catch (InvalidOperationException httpreq)
{
}
}
return Ok()
}
If you would like to just return List<SearchModel> from the actual response,you should not use var data = k.Value.SelectToken("").Children().First(); which will only retrieve the first element of docs array.
Try to foreach k.Value.SelectToken("").Children() and return List<SearchModel> instead of a SearchModel,refer to
[HttpGet("[action]/{query}")]
public async Task<IActionResult> Product(string query)
{
//initialize a list SearchModel
var modelList = new List<SearchModel>();
using (var client = new HttpClient())
{
try
{
client.BaseAddress = new Uri("http://xx.xx.xxx.xx:8080");
var response = await client.GetAsync($"/abc/xxx/select?q=title%3A%22{query}%22");
response.EnsureSuccessStatusCode();
var stringResult = await response.Content.ReadAsStringAsync();
var root = (JObject)JsonConvert.DeserializeObject(stringResult);
var items = root.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var item in items)
{
if (item.Key == "response")
{
var key = item.Value.SelectToken("").OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var k in key)
{
if (k.Key == "docs")
{
//remove .First()
var arrayData = k.Value.SelectToken("").Children();
foreach(var data in arrayData)
{
var model = new SearchModel();
var test = data.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value).ToList();
foreach (var t in test)
{
if (t.Key == "url")
{
model.Source = t.Value.ToString();
}
else if (t.Key == "title")
{
model.Title = t.Value.ToString();
}
}
modelList.Add(model);
}
}
}
}
}
return new JsonResult(modelList);
}
catch (InvalidOperationException httpreq)
{
}
}
return Ok();
}
Your model is not a list, but only a single object which you would overwrite continuously in your loop so that only one element remains.
Then you will need to iterate over all docs, not just use the first (e.g. k.Value.SelectToken("").Children().First()).
So you should be able to resolve your issue by changing your model to a List of SearchModels, and ensuring to iterate through all documents (it helps to inspect the variables in a debugger to see what happens).
An easier approach would be using JsonConvert, where you just would need to mirror the relevant structure of the JSON using C# classes, e.g.:
public class Document
{
public string Title;
public string Url;
}
public class Result
{
public Response response;
}
public class Response
{
public List<Document> docs;
}
then deserialize the json simple as:
var result = JsonConvert.DeserializeObject<Result>(stringResult);
and finally converting the result to your SearchModel:
var searchModels = result.response.docs.Select(x => new SearchModel {Source = x.Url, Title = x.Title}).ToList();

using a viewmodel to assign values from a soap web service to a dropdownlist

I need some advice on getting values from a soap web service to display in a dropdownlist using a viewmodel, I currently receive the data for the various dropdownlists from a service class found in a service class library project (n-tier application).
The code for the dropdownlist service follows a similar format to the code below:
public IEnumerable<SelectListItem> getValuesAsSelectItems(string selected)
{
var items = new List<SelectListItem>();
items.Add(new SelectListItem { Text = "Please Select", Value = string.Empty, Selected = (selected == string.Empty) });
foreach (var value in this.getValues())
{
items.Add(new SelectListItem { Text = value.Value, Value = value.Value, Selected = (selected == value.Value) });
}
return new SelectList(items, "Value", "Text");
}
I need a way of passing the values from this service to the viewmodel I have then created 7 controllers for each of the dropdownlist which will all link to partial views that I can reuse throughout the application, dropdownlists include titles, countries, states and others.
An approach you could take is to extract the drop down list values into a viewmodel of their own. So:
Step 1: Create a view model (ItemsViewModel) that encapsulates the drop down list items:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace Models
{
public class DropDownListItem
{
public string Text { get; set; }
public string Value { get; set; }
}
public class ItemsViewModel
{
private readonly List<DropDownListItem> _items;
// The selected item:
public string SelectedItem { get; set; }
// The items:
public IEnumerable<SelectListItem> Items
{
get
{
var allItems = _items.Select(i => new SelectListItem
{
Value = i.Value,
Text = i.Text
});
return DefaultItem.Concat(allItems);
}
}
// Default item (i.e. the "select" text) if none selected
public IEnumerable<SelectListItem> DefaultItem
{
get
{
return Enumerable.Repeat(new SelectListItem
{
Value = "-1",
Text = "Select an item"
}, count: 1);
}
}
public ItemsViewModel()
{
}
// Constructor taking in items from service and selected item string:
public ItemsViewModel(List<DropDownListItem> items, string selected)
{
_items = items;
SelectedItem = selected;
}
}
}
Step 2: Create a partial view in the Views folder that binds to the ItemsViewModel:
#model Models.ItemsViewModel
#Html.DropDownListFor(m => m.SelectedItem, Model.Items)
Step 3: In the appropriate controller (e.g. HomeController), place the child action that pulls the data from the service, the view model and the partial view together:
[ChildActionOnly]
public ActionResult DropDownList(string type, string selected)
{
// If you need to call different services based on the type (e.g. Country), then pass through "type" and base the call on that
var items = new ItemsViewModel(
(from g in _service.getTitles() select new DropDownListItem { Text = g.Text, Value = g.Value }).ToList(),
selected);
return PartialView("DropDownPartial", items);
}
Step 4: Drop this line of code into the view where you need the drop down list:
#Html.Action("DropDownList", "Home", new { selected = "2", type = "country" })
Note that selected and type are to be determined whichever way you see fit and are optional.
Hopefully this gives you some inspiration.