How to add object to database from an IEnumerable collection? - c#

I have a collection of ienumerable entities to be added to the database but it seems some conversion is needed. Can anyone point me in the right direction?
bool InsertDetails(DataTable detailTable, string fileName)
{
using (SunseapEBTContext context = new SunseapEBTContext())
{
if (InsertMaster(fileName))//if creating master record successful
{
int masterId = GetSPReadingM(m => m.FileName == fileName).SPReadingMasterId; //get MasterID of file uploaded
var details = detailTable.AsEnumerable().Select(row => new LeasingSPReadingDetailEntity()//new entity from datatable
{
//SPReadingId = row.Field<long>("ProductID"),
SPReadingMasterId = masterId,
BillCycleYear = int.Parse(row.Field<int>("Bill Cycle").ToString().Substring(0, 4)),
BillCycleMonth = byte.Parse(row.Field<byte>("Bill Cycle").ToString().Substring(4))
});
foreach(IEnumerable<LeasingSPReadingDetailEntity> detail in details)
{
context.LeasingSPReadingDetailEntities.AddObject(detail);
}
context.SaveChanges();
}
return true;
}
}
In the foreach loop, exception is thrown
CS1503 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable' to 'SunseapEBT.Domain.BillingModule.LeasingContract.Entity.LeasingSPReadingDetailEntity'
LeasingSPReadingDetailEntity class:
public class LeasingSPReadingDetailEntity
{
public long SPReadingId { get; set; }
public int SPReadingMasterId { get; set; }
public int BillCycleYear { get; set; }
public byte BillCycleMonth { get; set; }
}
More info:
A file which contains details is uploaded and will create a master record in one table. The details in the file are to be added to a separate table with the auto generated masterId from the first table. The issue is not being able to add the details into the database.
Edit:
I have found out why there was an error. The error was because of the contents of the file. Some rows had no values entered and the last row did not follow the format for the rest of the rows as it shows the total number of rows. Thanks all for the help!

#slawekwin comment is the answer. But I think there is a better solution, because it seems like your code is iterating 2x: 1st to generate new Enumerable (wasting memory), 2nd to add the object to context.
Might as well add the object directly when you iterate each rows.
foreach(var row in detailTable.AsEnumerable())
{
context.LeasingSPReadingDetailEntities.AddObject(
new LeasingSPReadingDetailEntity()//new entity from datatable
{
//SPReadingId = row.Field<long>("ProductID"),
SPReadingMasterId = masterId,
BillCycleYear = int.Parse(row.Field<string>("Bill Cycle").Substring(0, 4)),
BillCycleMonth = byte.Parse(row.Field<string>("Bill Cycle").Substring(4)),
AccountNumber = row.Field<string>("Account No."),
PeriodStart = row.Field<DateTime>("Period Start"),
PeriodEnd = row.Field<DateTime>("Period End"),
TownCouncil = row.Field<string>("Customer Name"),
Service = row.Field<string>("Service Type"),
Adjustment = row.Field<string>("Adjustment"),
Block = row.Field<string>("Blk"),
AddressLine1 = row.Field<string>("Adress Line 1"),
AddressLine2 = row.Field<string>("Adress Line 2"),
AddressLine3 = row.Field<string>("Postal Code"),
Usage = row.Field<decimal>("Usage"),
Rate = row.Field<decimal>("Rate"),
Amount = row.Field<decimal>("Amount")
}
);
}
--- EDIT ---
I am not sure, but I can guess that "Bill Cycle" field is neither int nor byte. Therefore, you should have retrieved it as string, then parse it to your new object. This is the part the I changed:
BillCycleYear = int.Parse(row.Field<string>("Bill Cycle").Substring(0, 4)),
BillCycleMonth = byte.Parse(row.Field<string>("Bill Cycle").Substring(4)),

You can change the problematic foreach loop to either of the below ones. I would prefer the first one as it is less verbose.
foreach(var detail in details)
{
context.LeasingSPReadingDetailEntities.AddObject(detail);
}
OR
foreach(LeasingSPReadingDetailEntity detail in details)
{
context.LeasingSPReadingDetailEntities.AddObject(detail);
}
If you look at the syntax of foreach loop, the very first construct variableType is type of the element being stored in the collection (LeasingSPReadingDetailEntity in your case) and NOT the type of the collection. You did the later which is why you are getting the invalid cast error.
foreach(variableType currentElementBeingIterated in collection){
//code block to operate on currentElement
}

Change it to List then add the item.
var details = detailTable.AsEnumerable().Select(row => new LeasingSPReadingDetailEntity()//new entity from datatable
{
SPReadingId = row.Field<long>("ProductID"),
SPReadingMasterId = masterId,
BillCycleYear = int.Parse(row.Field<int>("Bill Cycle").ToString().Substring(0, 4)),
BillCycleMonth = byte.Parse(row.Field<byte>("Bill Cycle").ToString().Substring(4)),
}).ToList();
foreach(var detail in details)
{
context.LeasingSPReadingDetailEntities.Add(detail);
}
or better still:
var details = detailTable.AsEnumerable().Select(row => new LeasingSPReadingDetailEntity()//new entity from datatable
{
SPReadingId = row.Field<long>("ProductID"),
SPReadingMasterId = masterId,
BillCycleYear = int.Parse(row.Field<int>("Bill Cycle").ToString().Substring(0, 4)),
BillCycleMonth = byte.Parse(row.Field<byte>("Bill Cycle").ToString().Substring(4)),
}).ToList();
context.LeasingSPReadingDetailEntities.AddRange(details);

Related

export file with asp.net

This project is an ASP.Net Api project with Angular. What I'm trying to do is export data from a database table and into an excel file. So far, I've managed to export all the table data into an excel file, but struggle to select 2 or 3 fields in the table to export.
[HttpGet("download")]
public IActionResult DownloadExcel(string field)
{
string dbFileName = "DbTableName.xlsx";
FileInfo file = new FileInfo(dbFileName);
byte[] fileContents;
var stream = new MemoryStream();
using (ExcelPackage package = new ExcelPackage(file))
{
IList<UserTable> userList = _context.UserTable.ToList();
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("DbTableName");
int totalUserRows = userList.Count();
}
return File(fileContents, fileType, dbFileName);
}
There's no need to write so many if ... else if ... else if ... else if ... to get the related field names.
A nicer way is to
Use a field list (IList<string>)as a parameter.
And then generate a required field list by intersect.
Finally, we could use reflection to retrieve all the related values.
Implementation
public IActionResult DownloadExcel(IList<string> fields)
{
// get the required field list
var userType = typeof(UserTable);
fields = userType.GetProperties().Select(p => p.Name).Intersect(fields).ToList();
if(fields.Count == 0){ return BadRequest(); }
using (ExcelPackage package = new ExcelPackage())
{
IList<UserTable> userList = _context.UserTable.ToList();
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("DbTableName");
// generate header line
for(var i= 0; i< fields.Count; i++ ){
var fieldName = fields[i];
var pi= userType.GetProperty(fieldName);
var displayName = pi.GetCustomAttribute<DisplayNameAttribute>()?.DisplayName;
worksheet.Cells[1,i+1].Value = string.IsNullOrEmpty(displayName ) ? fieldName : displayName ;
}
// generate row lines
int totalUserRows = userList.Count();
for(var r=0; r< userList.Count(); r++){
var row = userList[r];
for(var c=0 ; c< fields.Count;c++){
var fieldName = fields[c];
var pi = userType.GetProperty(fieldName);
// because the first row is header
worksheet.Cells[r+2, c+1].Value = pi.GetValue(row);
}
}
var stream = new MemoryStream(package.GetAsByteArray());
return new FileStreamResult(stream,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
}
}
You could configure the display name using the DsiplayNameAttribute:
public class UserTable
{
public int Id{get;set;}
[DisplayName("First Name")]
public string fName { get; set; }
[DisplayName("Last Name")]
public string lName { get; set; }
[DisplayName("Gender")]
public string gender { get; set; }
}
It's possible to add any properties as you like without hard-coding in your DownloadExcel method.
Demo :
passing a field list fields[0]=fName&fields[1]=lName&fields[2]=Non-Exist will generate an excel as below:
[Update]
To export all the fields, we could assume the client will not pass a fields parameter. That means when the fields is null or if the fields.Count==0, we'll export all the fields:
[HttpGet("download")]
public IActionResult DownloadExcel(IList<string> fields)
{
// get the required field list
var userType = typeof(UserTable);
var pis= userType.GetProperties().Select(p => p.Name);
if(fields?.Count >0){
fields = pis.Intersect(fields).ToList();
} else{
fields = pis.ToList();
}
using (ExcelPackage package = new ExcelPackage()){
....
}
}
if you want to use the datatable then we can define which you need to select from the datatable in this way
string[] selectedColumns = new[] { "Column1","Column2"};
DataTable dt= new DataView(fromDataTable).ToTable(false, selectedColumns);
or else if you wanna you list then you can use linq for selection of particular columns
var xyz = from a in prod.Categories
where a.CatName.EndsWith("A")
select new { CatName=a.CatName, CatID=a.CatID, CatQty = a.CatQty};

Viewbag is only grabbing information from final iteration of loop

I'm trying loop through a list and put the contents into a viewbag. My problem is that when I grab the viewbag in the view, it's only showing me the contents from the final iteration of the loop. Any ideas on what is happening? Here is an example:
var output = new List<AirportsInACity>();
foreach (var airport in cities)
{
var temp = new AirportsInACity();
temp.airportName = airport.name
temp.aircraftList = new List<AirportAircraftTypeList>();
foreach (aircraft in airport.aircraftTypes)
{
aircraftTemp = new AirportAircraftTypeList();
aircraftTemp.aircraftType = aircraft.AircraftType.AircraftTypeModel;
aircraftTemp.seats = aircraft.Seats;
aircraftTemp.attendants = aircraft.Attendants;
temp.aircraftList.Add(aircraftTemp);
}
output.Add(temp);
var outputStats = temp.AircraftList.GroupBy(p => p.aircraftType);
foreach (var item in outputStats)
{
ViewBag.AirportName = temp.name;
ViewBag.AirportAircraftType = item.Key;
ViewBag.AircraftSeatsSum = item.Sum(p => p.seats);
}
}
ViewBag.Output = output;
return PartialView(output);
Now, lets say I have this information:
Airport Name: JFK
Aircraft Type: Boeing777
Total Seats: 400
Airport Name: ATL
Aircraft Type: Boeing777
Total Seats: 800
Airport Name: LAS
Aircraft Type: Boeing727
TotalSeats: 150
The problem is that in my Viewbag, it's only grabbing the last chunk of information (the LAS airport) but the console is outputting all of the information. What could the issue be?
Here is an example of what the view looks like:
#foreach (var item in Viewbag.Output)
{
<td>#(ViewBag.AirportName)</td>
<td>#(ViewBag.AirportAircraftType)</td>
<td>#(ViewBag.AircraftSeatsSum)</td>
}
On ViewBag.Output you have a list of type AirportsInACity with these properties: airportName and aircraftList witch is a list of type AirportAircraftTypeList. Next you have a foreach into `outputStat' that setting always the SAME ViewBag item.
You must create a new viewmodel where put the outputStats
public class AircraftViewModel
{
public string AirportName {get; set; }
public string AirportAircraftType {get; set;}
public int AircraftSeatsSum {get; set; }
}
[..]
var outputStats = temp.AircraftList.GroupBy(p => p.aircraftType);
List<AircraftViewModel> vm = new List<AircraftViewModel>();
foreach (var item in outputStats)
{
var aircraft = new AircraftViewModel();
aircraft.AirportName = temp.name;
aircraft.AirportAircraftType = item.Key;
aircraft.AircraftSeatsSum = item.Sum(p => p.seats);
vm.Add(aircraft);
}
}
ViewBag.Output = vm;
Create ExpandoObject and add it to the Details List.
Example:
Controller Code:
List<dynamic> Details = new List<dynamic>();
foreach (var item in outputStats)
{
dynamic detail;
detail = new ExpandoObject();
detail.AirportName =temp.name;
detail.AirportAircraftType = item.Key;
detail.AircraftSeatsSum =item.Sum(p => p.seats);
Details.Add(detail);
}
ViewBag.Details = Details;
View Code:
#foreach (dynamic detail in ViewBag.Details)
{
<td>#(detail.AirportName)</td>
<td>#(detail.AirportAircraftType)</td>
<td>#(detail.AircraftSeatsSum)</td>
}

Create an Array from SQL Query Results

I have the following function that searches a database for entries where a column called "description" have the same value. Right now it just returns the first value it finds or a default value is there isn't one.
public static NewCode GetAltCode(int altCodeVer, string descrip)
{
var sql = #"select Code, Description, VersionID from Code.CodeLookup where versionid=#vers and description=#description";
return ObjectFactory.GetInstance<IDatabaseFactory>().Query<NewCode>(sql, new { vers = altCodeVer, description = descrip, }).FirstOrDefault();
}
I have this if statement to check and make sure the result isn't null, and if it is, to say that the "code isn't found"
[Authorize(parentAction: "Edit")]
public ActionResult Lookup(string Code, int? VersionId = null)
{
var Info = VisitViews.GetDescriptionByVersionId(Code, VersionId.HasValue ? VersionId.Value : 9);
var description = string.Empty;
// CHECK FOR NULL
if (Info != null)
{
description = Info.Description;
if (VersionId == 9)
{
var altInfo = VisitViews.GetAltCode(10, description);
}
if (VersionId == 10)
{
var altInfo = VisitViews.GetAltCode(9, description);
}
}
else
description = "CODE NOT FOUND";
return Json(new { Description = description });
}
My question is, instead of doing FirstOrDefault, is there a way to store the results in an array (or even to store them in a list and call ToArray on the list)? I'm trying to get all of the codes received during the sql search instead of just one so that another function I am working on can traverse the array and place the items where they need to be in a UI.
For future reference of this post, here is the answer:
Change the return type to NewCode[] and replace .FirstOrDefault() with .ToArray()
public static NewCode[] GetAltCode(int altCodeVer, string descrip)
{
var sql = #"select Code, Description, VersionID from Code.CodeLookup where versionid=#vers and description=#description";
return ObjectFactory.GetInstance<IDatabaseFactory>().Query<NewCode>(sql, new { vers = altCodeVer, description = descrip, }).ToArray();
}

How to pick second column from a PetaPoco query result?

Below is my code:
string Query = "SELECT EmpName, EmpCode FROM EmpDetail WHERE ZCode=101 ORDER BY EmpName";
var db = new PetaPoco.Database("conCustomer");
var result = db.Fetch<string>(query);
TextBox1.Text = result.ToString(); //This is giving first column
TextBox2.Text = .... // pick second column
I want to know how to pick the second column from the result.
I believe the issue you're having is that you're not using a class as part of the fetch. Try creating a simple class and performing the fetch with that:
public class EmpDetail
{
public string EmpName { get; set; }
public string EmpCode { get; set; }
}
var result = db.Fetch<EmpDetail>(Query);
Then try iterating over that list of EmpDetail:
foreach (var detail in result)
{
var x = detail.EmpName; // First column
var y = detail.EmpCode; // Second column
}
EDIT: According to this (h/t Robert Koritnik), it does look like it will support a dynamic query like so (untested):
foreach (var detail in db.Fetch<dynamic>(query))
{
var x = detail.EmpName; // First column
var y = detail.EmpCode; // Second column
}

Flatten One-to-Many Relationship Using Dynamic LINQ

Is it possible to flatten a one-to-many relationship using dynamic LINQ?
For example, I might have a list of Users and the User class contains a list of many UserPreferences. The UserPreference class is essentially a name/value pair.
A user will define what types of user preferences are available for a group of users.
public class User
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public IList<UserPreference> UserPreferences
{
get;
set;
}
}
public class UserPreference
{
public UserPreference(string name, object userValue)
{
this.Name = name;
this.UserValue = userValue;
}
public string Name
{
get;
set;
}
public object UserValue
{
get;
set;
}
}
Therefore one user group might be defined in the following way:
List<User> users = new List<User>();
User user1 = new User();
user1.FirstName = "John";
user1.LastName = "Doe";
user1.UserPreferences.Add(new UserPreference("Favorite color", "Red"));
User user2 = new User();
user2.FirstName = "Jane";
user2.LastName = "Doe";
user2.UserPreferences.Add(new UserPreference("Favorite mammal", "Dolphin"));
user2.UserPreferences.Add(new UserPreference("Favorite color", "Blue"));
users.Add(user1);
users.Add(user2);
return users;
The desired output would be:
First Name Last Name Favorite Color Favorite Mammal
John Doe Red NULL
Jane Doe Blue Dolphin
Is there a way to create an anonymous type so that UserPreferences would get rolled up into the User?
For example,
var u = UserScopedSettingAttribute.Select("new (FirstName as FirstName, UserValue as FavoriteColor)", null);
string name = u.FirstName;
string color = u.FavoriteColor;
Ultimately this list of Users will get bound to an ASP.NET GridView web control. There will be a large volume of data involved in this operation and performance will be critical.
Any suggestions are appreciated!
I know it doesn't exactly answer your question, but compiling strings into new classes at runtime like dlinq does has always had kind of a bad smell to it. Consider just simply using a DataTable like this,
DataTable prefs = new DataTable();
IEnumerable<DataColumn> cols = (from u in users
from p in u.UserPreferences
select p.Name)
.Distinct()
.Select(n => new DataColumn(n));
prefs.Columns.Add("FirstName");
prefs.Columns.Add("LastName");
prefs.Columns.AddRange(cols.ToArray());
foreach (User user in users)
{
DataRow row = prefs.NewRow();
row["FirstName"] = user.FirstName;
row["LastName"] = user.LastName;
foreach (UserPreference pref in user.UserPreferences)
{
row[pref.Name] = pref.UserValue;
}
prefs.Rows.Add(row);
}
This should do it. Flattening is generally done with SelectMany extension method, but in this case I am using a let expression. The code to remove the null preferences is a bit ugly and could prob be improved but it works:
var flattenedUsers = from user in GetUsers()
let favColor = user.UserPreferences.FirstOrDefault(pref => pref.Name == "Favorite color")
let favMammal = user.UserPreferences.FirstOrDefault(pref => pref.Name == "Favorite mammal")
select new
{
user.FirstName,
user.LastName,
FavoriteColor = favColor == null ? "" : favColor.UserValue,
FavoriteMammal = favMammal == null ? "" : favMammal.UserValue,
};
My best suggestion would be to not use dynamic LINQ, but add a flatuser class and then loop through the users. The code for this is simple, and if you were able to get a linq query with similar results it would generate the same code, although you can't really tell how optimized it would be as it might involve some joins that would incur a performance penalty instead of just looping. If you were pulling this from a database using LINQ to SQL then you could use an entity relation to to get the data using linq instead of this loop.
Loop:
List<FlatUser> flatusers = new List<FlatUser>();
foreach (User u in users)
{
foreach (UserPreference up in u.UserPreferences)
{
flatusers.Add(new FlatUser
{
FirstName = u.FirstName,
LastName = u.LastName,
Name = up.Name,
UserValue = up.UserValue
});
}
}
Flat User Class:
public class FlatUser
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public string Name
{
get;
set;
}
public object UserValue
{
get;
set;
}
}
Unfortunately
var u = UserScopedSettingAttribute.Select("new {FirstName as FirstName, UserValue as FavoriteColor}", null);
string name = u.FirstName;
string color = u.FavoriteColor;
won't work. When you use DLINQ Select(string) the strongest compile time class information you have is Object, so u.FirstName will throw a compile error. The only way to pull the properties of the runtime generated anonymous class is to use reflection. Although, if you can wait, this will be possible with C# 4.0 like this,
dynamic u = UserScopedSettingAttribute.Select("new {FirstName as FirstName, UserValue as FavoriteColor}", null);
string name = u.FirstName;
string color = u.FavoriteColor;
I think the pragmatic answer here is to say your attempting to force C# to become a dynamic language and any solution is going to be really pushing C# to its limits. Sounds like your trying to transform a database query of columns that are only determined at query time into a collection that is based on those columns and determined at run time.
Linq and Gridview binding is really pretty and succinct and all but you have to start thinking about weighing the benefit of getting this compiler bending solution to work just so you don't have to dynamically generate gridview rows and columns by yourself.
Also if your concerned about performance I'd consider generating the raw HTML. Relying on the collection based WebForms controls to efficiently display large sets of data can get dicey.
You add in a couple of OnItemDataBound events and boxing and unboxing is going to really gum up the works. I'm assuming too your going to want to add interactive buttons and textboxes to the rows as well and doing 1000 FindControls has never been fast.
There are probably more efficient ways to do this, but to actually answer your question, I came up with the following code. (Note that I've never worked with DynamicLinq before, so there may be a better way to use it to accomplish your goal.)
I created a console application, pasted in the classes from your post, then used the following code.
static void Main(string[] args)
{
var users = GetUserGroup();
var rows = users.SelectMany(x => x.UserPreferences.Select(y => new { x.FirstName, x.LastName, y.Name, y.UserValue }));
var userProperties = rows.Select(x => x.Name).Distinct();
foreach (var property in userProperties)
{
Console.WriteLine(property);
}
Console.WriteLine();
// The hard-coded variety.
var results = users.Select(x => new
{
x.FirstName,
x.LastName,
FavoriteColor = x.UserPreferences.Where(y => y.Name == "Favorite color").Select(y => y.UserValue).FirstOrDefault(),
FavoriteAnimal = x.UserPreferences.Where(y => y.Name == "Favorite mammal").Select(y => y.UserValue).FirstOrDefault(),
});
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The dynamic variety.
DynamicProperty[] dynamicProperties = new DynamicProperty[2 + userProperties.Count()];
dynamicProperties[0] = new DynamicProperty("FirstName", typeof(string));
dynamicProperties[1] = new DynamicProperty("LastName", typeof(string));
int propIndex = 2;
foreach (var property in userProperties)
{
dynamicProperties[propIndex++] = new DynamicProperty(property, typeof(string));
}
Type resultType = ClassFactory.Instance.GetDynamicClass(dynamicProperties);
ConstructorInfo constructor = resultType.GetConstructor(new Type[] {});
object[] constructorParams = new object[] { };
PropertyInfo[] propInfoList = resultType.GetProperties();
PropertyInfo[] constantProps = propInfoList.Where(x => x.Name == "FirstName" || x.Name == "LastName").OrderBy(x => x.Name).ToArray();
IEnumerable<PropertyInfo> dynamicProps = propInfoList.Where(x => !constantProps.Contains(x));
// The actual dynamic results creation.
var dynamicResults = users.Select(user =>
{
object resultObject = constructor.Invoke(constructorParams);
constantProps[0].SetValue(resultObject, user.FirstName, null);
constantProps[1].SetValue(resultObject, user.LastName, null);
foreach (PropertyInfo propInfo in dynamicProps)
{
var val = user.UserPreferences.FirstOrDefault(x => x.Name == propInfo.Name);
if (val != null)
{
propInfo.SetValue(resultObject, val.UserValue, null);
}
}
return resultObject;
});
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Display the results.
var displayResults = dynamicResults;
//var displayResults = results;
if (displayResults.FirstOrDefault() != null)
{
PropertyInfo[] properties = displayResults.First().GetType().GetProperties();
int columnWidth = Console.WindowWidth / properties.Length;
int index = 0;
foreach (PropertyInfo property in properties)
{
Console.SetCursorPosition(index++ * columnWidth, Console.CursorTop);
Console.Write(property.Name);
}
Console.WriteLine();
foreach (var result in displayResults)
{
index = 0;
foreach (PropertyInfo property in properties)
{
Console.SetCursorPosition(index++ * columnWidth, Console.CursorTop);
Console.Write(property.GetValue(result, null) ?? "(null)");
}
Console.WriteLine();
}
}
Console.WriteLine("\r\nPress any key to continue...");
Console.ReadKey();
}
static List<User> GetUserGroup()
{
List<User> users = new List<User>();
User user1 = new User();
user1.FirstName = "John";
user1.LastName = "Doe";
user1.UserPreferences = new List<UserPreference>();
user1.UserPreferences.Add(new UserPreference("Favorite color", "Red"));
user1.UserPreferences.Add(new UserPreference("Birthday", "Friday"));
User user2 = new User();
user2.FirstName = "Jane";
user2.LastName = "Doe";
user2.UserPreferences = new List<UserPreference>();
user2.UserPreferences.Add(new UserPreference("Favorite mammal", "Dolphin"));
user2.UserPreferences.Add(new UserPreference("Favorite color", "Blue"));
users.Add(user1);
users.Add(user2);
return users;
}

Categories