Is there a way to append a calculated field to Select()? - c#

Is there a way to add a field to an IQueryable (or List<> or whatever) without having to rewrite an entire "new {list, of, all, fields}". I have a dynamic field who can have different formulas depending on the situation. Here's a basic example :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
List<User> users = new List<User>();
users.Add(new User { FirstName = "Foo", LastName = "Bar"} );
users.Add(new User { FirstName = "Bar", LastName = "Foo"} );
I would like to add a field later ( just before the output ) without removing or rewriting all the existing fields
var betterUser = users.Select(u => new { FullName = u.FirstName + " " + u.LastName });
This will only return FullName, but I want to keep FirstName and LastName. In my real code, I have about 15 fields and about 1.2 billion rows that will be cleaned up before adding the last field so if I add all possible calculated fields directly to the model, the performance takes a serious hit.

You could do something like this
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public object dynamicField {get; set;}
}
List<User> users = new List<User>();
users.Add(new User { FirstName = "Foo", LastName = "Bar"} );
users.Add(new User { FirstName = "Bar", LastName = "Foo"} );
foreach (var obj in users)
{
obj.dynamicField = obj.FirstName + " " + obj.LastName;
}
This way you would not have to remove or rewrite all the existing fields.

Your user class needs a property to do this: but you can do it:
public class Animal
{
public string Name { get; set; }
public bool HasLegs { get; set; }
public bool IsFoo { get; set; }
public string FooLegs { get; set; }
}
private static string legsString(bool hasLegs)
{
return hasLegs ? "Has Legs" : "Has No Legs";
}
static void Main(string[] args)
{
List<Animal> animals = new List<Animal>()
{
new Animal()
{
Name = "Foo",
HasLegs = true
},
new Animal()
{
Name = "Kangaroo",
HasLegs = true
},
new Animal()
{
Name = "Snake",
HasLegs = false
}
};
var fooAnimals = animals.Select(s => new Animal
{
Name = s.Name,
HasLegs = s.HasLegs,
IsFoo = (s.Name == "Foo" && s.HasLegs),
FooLegs = $"{s.Name} {legsString(s.HasLegs)}"
}).AsQueryable<Animal>();
}
}

Related

With httpPut to skip that column if .net core is null or null

I am developing micro-service with .NET Core.
The following code is working with an HttpPut request.
But if any field has empty or null value in our incoming JSON request, I want it to retrieve the previous value.
I don't want to constantly run the code below. Is there a short way around this?
if(updateCustomer.Surname != null && updateCustomer.Surname !=string.Empty)
{
customer.Surname = updateCustomer.Surname;
}
var serviceResponse = new ServiceResponse<GetCustomerDto>();
Customer customer = await _context.Customers.FirstOrDefaultAsync(c => c.Id == updateCustomer.Id);
var persons = (from p in _context.Customers where p.Id == updateCustomer.Id select p);
foreach (var person in persons)
{
person.Name = updateCustomer.Name;
person.Surname = updateCustomer.Surname;
person.BusinessCode = "123";
person.Phone = updateCustomer.Phone;
}
await _context.SaveChangesAsync();
serviceResponse.Data = _mapper.Map<GetCustomerDto>(customer);
Following the GetValueOrDefault() idiom from Nullable types, you can create a string extension method to select between two values like so:
public static class StringExtensions
{
public static string GetValueOrDefault(this string str, string alternative)
{
if(string.IsNullOrEmpty(str))
{
return alternative;
}
return str;
}
}
public class Program
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string BusinessCode { get; set; }
public string Phone { get; set; }
}
public static void Main()
{
Person previous = new Person
{
Name = null,
Surname = "Smith",
BusinessCode = "123",
Phone = "(555) 123-4567"
};
Person current = new Person
{
Name = "John",
Surname = string.Empty,
BusinessCode = "321",
Phone = "(555) 765-4321"
};
Person updated = new Person
{
Name = current.Name.GetValueOrDefault(previous.Name),
Surname = current.Surname.GetValueOrDefault(previous.Surname),
BusinessCode = current.BusinessCode.GetValueOrDefault(previous.BusinessCode),
Phone = current.Phone.GetValueOrDefault(previous.Phone)
};
}
}

how to get Json nested properties to primary one

I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.

How merge two lists of different objects?

Using C# with LINQ, how can I merge two lists of different objects, say, Seminar and Conference?
They have some common and some different fields/properties and do not share unique id.
class Seminar
{
int id,
DateTime joinDate,
string name
}
class Conference
{
Guid confNumber,
DateTime joinDate
Type type
}
I have a list of:
List<Seminar>
List<Conference>
I need to merge them into a super List:
List<Object>
A code snippet would be great help.
If you just want a single List<object> containing all objects from both lists, that's fairly simple:
List<object> objectList = seminarList.Cast<object>()
.Concat(conferenceList)
.ToList();
If that's not what you want, then you'll need to define what you mean by "merge".
Following code works fine for me, if this is your definition of Merge
One solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = new A() } };
List<Object> allS = (from x in someAs select (Object)x).ToList();
allS.AddRange((from x in someBs select (Object)x).ToList());
Where A and B are some classes as follows
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public A something { get; set; }
}
Another Solution
List<A> someAs = new List<A>() { new A(), new A() };
List<B> someBs = new List<B>() { new B(), new B { something = string.Empty } };
List<Object> allS = (from x in someAs select (Object)new { someAnotherThing = x.someAnotherThing, something = string.Empty }).ToList();
allS.AddRange((from x in someBs select (Object)new { someAnotherThing = string.Empty, something = x.something}).ToList());
Where A and B are having class definition as
class A
{
public string someAnotherThing { get; set; }
}
class B
{
public string something { get; set; }
}
Simple method of pure code
internal class Person
{
public int Id { get; set; }
public string UserName { get; set; }
}
internal class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
internal class UserPerson
{
public int Id { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
private static void Main(string[] args)
{
Person[] people = new Person[3] { new Person { Id = 1, UserName = "AliUserName" }, new Person { Id = 2, UserName = "MortezaUserName" }, new Person { Id = 3, UserName = "SalarUserName" } };
User[] users = new User[4] { new User { FirstName = "ali", LastName = "Barzegari" }, new User { FirstName = "Morteza", LastName = "Sefidi" }, new User { FirstName = "Salar", LastName = "Pirzadeh" }, new User { FirstName = "Babak", LastName = "Hasani" } };
UserPerson[] userPeople = new UserPerson[people.Length > users.Length ? people.Length : users.Length];
if (people.Length > users.Length)
for (int i = 0; i < people.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people[i].Id,
UserName = people[i].UserName,
FirstName = users.Length <= i ? "" : users[i].FirstName,
LastName = users.Length <= i ? "" : users[i].LastName
};
}
else
for (int i = 0; i < users.Length; i++)
{
userPeople[i] = new UserPerson
{
Id = people.Length <= i ? 0 : people[i].Id,
UserName = people.Length <= i ? "" : people[i].UserName,
FirstName = users[i].FirstName,
LastName = users[i].LastName
};
}
Console.ReadLine();
}

Compare Two Arrays

I'm trying to compare 2 object arrays to check whether the values have changed between them. e.g.
var oldState = new object[] { 1, "Lee", 0, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName "User" } };
var newState = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
Each item in the array represents a value for a property from the User class below (in the order they are defined):
public class User {
public int UserID { get; set; }
public string UserName { get; set; }
[IgnoreAudit]
public int NumViews { get; set; }
[ChildAudit]
public UserProfile Profile { get; set; }
public Role Role { get; set; }
}
public class UserProfile {
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Role {
public int RoleID { get; set; }
public string RoleName { get; set; }
}
I need to create a method to compare the 2 objects. e.g.
public bool IsDirty(object[] oldState, object[] newState) {
// Comparision code here
}
The complicated part is that it only compares the simple properties that don't have the IgnoreAudit attribute applied to them and only compares complex properties that have ChildAudit attribute applied.
Therefore from the example above the Profile property would be recursively compared (since it has the ChildAudit attribute applied) whereas the Role property wouldn't. Also say if NumViews is the only value that changes between the old and new state IsDirty would return false (since it has the IgnoreAudit attribute applied).
To help you further, given the old state above here is a few examples of the new state and whether IsDirty would return true or false:
// False - since only NumViews changed
var newState1 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// True - since Username has changed
var newState2 = new object[] { 1, "Lee2", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// True - since Profile.FirstName has changed
var newState3 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Paul",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "User" } };
// False - since only Role.RoleName has changed
var newState4 = new object[] { 1, "Lee", 1, new UserProfile { FirstName = "Lee",
LastName = "Timmins" }, new Role { RoleID = 1, RoleName = "Admin" } };
I hope i've made my intentions clear. Please feel free to comment if there's any additional information you require.
Appreciate the helps. Thanks
You can use the IComparable Interface to determine if two classes are equal.
class Program
{
static void Main(string[] args)
{
var newState1 = new User
{
UserId = 1,
UserName = "Lee",
NumViews = 1,
Profile = new UserProfile
{
FirstName = "Lee",
LastName = "Timmins"
},
RoleMember = new Role {RoleId = 1, RoleName = "User"}
};
// True - since Username has changed
var newState2 = new User
{
UserId = 1,
UserName = "Lee2",
NumViews = 1,
Profile = new UserProfile
{
FirstName = "Lee",
LastName = "Timmins"
},
RoleMember = new Role {RoleId = 1, RoleName = "User"}
};
//Will show 1 or -1 if not state has change. If == 0 then state has not changed.
Console.WriteLine("Has State1 Changed? : {0}", newState1.CompareTo(newState2));
Console.ReadLine();
}
public class User : IComparable<User>
{
public int UserId { get; set; }
public string UserName { get; set; }
public int NumViews { get; set; }
public UserProfile Profile { get; set; }
public Role RoleMember { get; set; }
#region Implementation of IComparable<in User>
public int CompareTo(User other)
{
if (UserId.CompareTo(other.UserId) != 0)
{
return UserId.CompareTo(other.UserId);
}
if (UserName.CompareTo(other.UserName) != 0)
{
return UserName.CompareTo(other.UserName);
}
if (NumViews.CompareTo(other.NumViews) != 0)
{
return NumViews.CompareTo(other.NumViews);
}
if (Profile.CompareTo(other.Profile) != 0)
{
return Profile.CompareTo(other.Profile);
}
return RoleMember.CompareTo(other.RoleMember) != 0 ? RoleMember.CompareTo(other.RoleMember) : 0;
}
#endregion
}
public class UserProfile : IComparable<UserProfile>
{
public string FirstName { get; set; }
public string LastName { get; set; }
#region Implementation of IComparable<in UserProfile>
public int CompareTo(UserProfile other)
{
return FirstName.CompareTo(other.FirstName) == 0 ? LastName.CompareTo(other.LastName) : FirstName.CompareTo(other.FirstName);
}
#endregion
}
public class Role : IComparable<Role>
{
public int RoleId { get; set; }
public string RoleName { get; set; }
#region Implementation of IComparable<in Role>
public int CompareTo(Role other)
{
return RoleId.CompareTo(other.RoleId) == 0 ? RoleName.CompareTo(other.RoleName) : RoleId.CompareTo(other.RoleId);
}
#endregion
}
}

Linq join 3 list <T>

I have three lists that I need to join together
class Person
{
public int PersonID{ get; set; }
public string FirstName{get; set;}
public string LastName {get; set;}
}
class Traffic
{
public DateTime Date{ get; set; }
public int PersonID;
public int TrafficID;
}
class TrafficType
{
public int TrafficID { get; set; }
public string Description { get; set; }
}
List<Person> Persons=GetPersons();
List<TrafficType> TrafficTypes=GetTrafficTypes();
List<Traffic> Traffics=GetTraffics();
I need an output like:
PersonID FirstName LastName Date Description
1001 David ... 2011/07/19 sample description
from person in Persons
from traffic in traffics
from trafficType in trafficTypes
where trafficType.TrafficID = traffic.TrafficID
where traffic.PersonID = person.PersonID
select new
{
PersonID = person.PersonID,
....
}
var result = Persons.Join(
Traffics,
person => person.PersonID,
trafic => trafic.PersonID,
(person, trafic) => new
{
PersonId = person.PersonID,
FirstName = person.FirstName,
LastName = person.LastName,
Date = trafic.Date,
TraficId = trafic.TrafficID
}).Join(
TrafficTypes,
a => a.TraficId,
traficType => traficType.TrafficID,
(a, traficType) => new
{
PersonId = a.PersonId,
FirstName = a.FirstName,
LastName = a.LastName,
Date = a.Date,
Description = traficType.Description
});
Here's a complete code sample with Linq query expression code that should get exactly what you're looking for:
using System;
using System.Collections.Generic;
using System.Linq;
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Traffic
{
public DateTime Date { get; set; }
public int PersonId { get; set; }
public int TrafficId { get; set; }
}
class TrafficType
{
public int Id { get; set; }
public string Description { get; set; }
}
class Program
{
static void Main(string[] args)
{
var persons = new List<Person>()
{
new Person()
{
Id = 1001,
FirstName = "David",
LastName = "Jones",
},
};
var trafficTypes = new List<TrafficType>()
{
new TrafficType()
{
Id = 456,
Description = "sample description",
},
};
var traffics = new List<Traffic>()
{
new Traffic()
{
PersonId = 1001,
TrafficId = 456,
Date = DateTime.Now,
},
};
var joinedData = from p in persons
from t in traffics
from tt in trafficTypes
where p.Id == t.PersonId
&& tt.Id == t.TrafficId
select new
{
PersonId = p.Id,
FirstName = p.FirstName,
LastName = p.LastName,
// Remove time component, if present
Date = t.Date.Date,
Description = tt.Description,
};
foreach (var item in joinedData)
{
Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}"
, item.PersonId
, item.FirstName
, item.LastName
, item.Date.ToShortDateString() // Don't print the time
, item.Description
);
}
}
}
The program output is:
1001 David Jones 7/19/2011 sample description
You can put them all in a class e.g. (Problem), then use a method for your output.
class Problem
{
public Problem()
{
}
public void Show()
{
// implement your output here
}
}
Or, if you are using Windows Forms app and interisting in Tables, you can use DataGridView control. For more information about it, visit http://msdn.microsoft.com/en-us/library/e0ywh3cz.aspx
Or, use DataGrid: http://www.codeproject.com/KB/grid/usingdatagrid.aspx

Categories