Separate class for the same purpose - c#

I have this class
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<string> Blessings;
}
I am Getting the response of the two lists this way:
public async Task<List<BlessingDTO>> GetBlessing(string UserType)
{
string blessing = "Blessing_" + UserType;
List<BlessingDTO> results = new List<BlessingDTO>();
using (DTS_OnlineContext context = new DTS_OnlineContext())
{
var items = await context.Messages.AsNoTracking().Where(x => x.MessageContext == blessing).GroupBy(x=>x.GroupKey).Select(b=>b.OrderBy(x=>x.Sort)).ToListAsync();
if (items.Count() > 0)
{//Notes.Select(x => x.Author).Distinct();
results = items.ToList().ConvertAll(x => new BlessingDTO()
{ BlessingCategoryName = x.ToList().Select(y => y.MessageName).Distinct().ToList(),
Blessings = x.ToList().Select(y => y.MessageText).ToList()
});
}
}
return results;
}
if I am changing the class, for my porpuse to be:
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<bless> Blessings;
}
public class bless
{
public string text;
public int length;
}
how can I initialize the new class ?
Blessings = new bless
won't give the results. how can I save the data to bring them in the response

Let's focus in this part:
items
.ToList()
.ConvertAll(x =>
new BlessingDTO()
{
BlessingCategoryName = x.ToList().Select(y => y.MessageName).Distinct().ToList(),
Blessings = x.ToList().Select(y => y.MessageText).ToList()
}
);
where items is probably a List<List<Message>>, thus x being a List<Message>.
Now what is causing an error is the following: Blessings = x.ToList().Select(y => y.MessageText).ToList(). This creates a new list for the list of messages, then selects the MessageText from that list, which results in IEnumerable<string>. In the end a new list is created for these strings. This list of strings isn't assignable to List<bless>, thus will generate an error.
What you want is a result of List<bless>, so we need to convert the List<Message> list into a List<bless> somehow. We know how to do that, namely with a select: x.Select(message => new bless()).ToList(). All we have to do is fill in the properties of bless: x.Select(message => new bless { text = message.MessageText }).ToList(). The other property is up to you.

You can initialise the list like this:
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<bless> Blessings = new List<bless>();
}
Although, I would recommend these fields are changes to properties, as that is more idiomatic in C#
public class BlessingDTO
{
public List<string> BlessingCategoryName {get;set;}
public List<bless> Blessings {get;set;} = new List<bless>();
}

Related

Order by multiple lists of object

I've three lists in an object and want to perform order by operation using LINQ
object containing lists
public class ApplicationCommunications
{
public ApplicationCommunications()
{
listNotification = new List<ApplicationNotifications>();
listEmail = new List<ApplicationEmail>();
listSMS = new List<ApplicationSMS>();
}
public List<ApplicationNotifications> listNotification { get; set; }
public List<ApplicationEmail> listEmail { get; set; }
public List<ApplicationSMS> listSMS { get; set; }
}
Getting data from db
ApplicationCommunications applicationCommunications = new ApplicationCommunications();
applicationCommunications.listNotification = GetApplicationNotification(applicationId).Select(c => new ApplicationNotifications
{
NotificationId = c.NotificationId,
Message = c.Message,
SendDate = c.SendDate.Value
}).ToList();
applicationCommunications.listEmail = GetApplicationEmails(applicationId).Select(t => new ApplicationEmail
{
EmailContent = t.Body,
EmailAddress = t.Email,
SendDate = t.SendDate.Value,
}).ToList();
applicationCommunications.listSMS = GetApplicationMessage(applicationId).Select(t => new ApplicationSMS
{
SMSContent = t.Body,
PhoneNumber = t.Phone,
SendDate = t.SendDate.Value,
}).ToList();
We've three lists each list of the object has "senddate" property now I want to make a new list from these three lists where we will have data in order. Is that possible?
How we can perform order by with send date? simply I want to display data in order.
Select method gives you Enumerable type of list. Enumerable can be ordered by OrderBy, so simply do this
applicationCommunications.listNotification = GetApplicationNotification(applicationId).Select(c => new ApplicationNotifications
{
NotificationId = c.NotificationId,
Message = c.Message,
NotificationSendDate = c.SendDate.Value
})
.OrderBy(an => an.NotificationSendDate)
.ThenBy(an => an.NotificationId)
.ToList();
EDIT:
You can read more here https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby?view=net-5.0
pardon for the incomplete question. We've three lists each list of the
object has "senddate" property now I want to make a new list from
these three lists where we will have data in order. Is that possible?
As shown in the other answer you need OrderBy:
List<DateTime> orderedSendDates = applicationCommunications.listNotification
.Select(x => x.NotificationSendDate)
.Concat(applicationCommunications.listEmail.Select(x => x.EmailSendDate))
.Concat(applicationCommunications.listSMS.Select(x => x.SMSSendDate))
.OrderBy(dt => dt)
.ToList();
If you want unique DateTimes use Distinct before the OrderBy.
If you don't have these properties initialized when you want the list you could do:
List<DateTime> orderedSendDates =
GetApplicationNotification(applicationId).Select(x => x.SendDate)
.Concat(GetApplicationEmails(applicationId).Select(x => x.SendDate))
.Concat(GetApplicationMessage(applicationId).Select(x => x.SendDate))
.Where(sendDateOrNull => sendDateOrNull.HasValue)
.Select(sendDateOrNull => sendDateOrNull.Value)
.OrderBy(dt => dt)
.ToList();
If you want a big list containing the different types of elements, ordered by sendDate (but not just a list of dateTime), you may first create a common type for that :
public class SentElement {
public string ElementDescription {get ; set;}
public DateTime SendDate { get; set;}
}
Then map your different types to the common type using Select, filling the description the way you want for each type of element:
var listNotification = GetApplicationNotification(applicationId).Select(c => new SentElement
{
ElementDescription = c.NotificationId + c.Message,
SendDate= c.SendDate.Value
}).ToList();
var listEmail = GetApplicationEmails(applicationId).Select(t => new SentElement
{
ElementDescription = t.EmailContent + t.EmailAddress,
SendDate = t.SendDate.Value,
}).ToList();
var listSMS = GetApplicationMessage(applicationId).Select(t => new SentElement
{
ElementDescription = t.Body + t.Phone,
SendDate = t.SendDate.Value,
}).ToList();
And finally merging and ordering the result :
var mergedList = listNotification.Concat(listEmail).Concat(listSMS).OrderByDescending(t=> t.SendDate);

Mapping dependent observable to sub list

Say I have the following two observable streams
IObservable<LibraryView> GetLibrariesSource();
IObservable<FolderView> GetLibraryFolderSource(LibraryView library);
so IObservable<FolderView> depends upon a LibraryView. Also these views are flat, i.e. they have no navigational properties.
How would I map these two streams to an IObservable<Library> stream, where Library has a list of Folders
public class Library
{
public List<Folder> Folders { get; set; }
}
Assuming that I can easily map from a LibraryView to a Library and from a FolderView to a Folder.
Also, My end goal is to simply get a List<Library> using e.g., ForEachAsync. So it may not be necessary to create an IObservable<Library>.
Assuming your problem space looks like this:
async Task Do()
{
var libraryMapper = new Func<LibraryView, Library>(lv => /*implement me*/ new Library());
var folderMapper = new Func<FolderView, Folder>(fv => /*implement me*/ new Folder());
var librariesSource = new Func<IObservable<LibraryView>>(() => /*implement me*/ Observable.Empty<LibraryView>());
var libraryFolderSource = new Func<LibraryView, IObservable<FolderView>>(lv => /*implement me*/ Observable.Empty<FolderView>());
}
public class Library
{
public List<Folder> Folders { get; set; }
}
public class Folder { }
public class LibraryView { }
public class FolderView { }
Then something like this will work inside Do():
var libraryList = await librariesSource()
.Select(lv => (LibraryView: lv, FolderViewObservable: libraryFolderSource(lv)))
.SelectMany(async t => (LibraryView: t.LibraryView, FolderViews: await t.Item2.ToList()))
.Select(t =>
{
var newLibrary = libraryMapper(t.LibraryView);
newLibrary.Folders = t.FolderViews.Select(fv => folderMapper(fv)).ToList();
return newLibrary;
})
.ToList();
Use Select to map, SelectMany to apply await calls, and await to get from IObservable<IList<T>> to IList<T>.

Populating SubModels using LINQ

I have a list of object which is something like this
[Code Type][condition Type][Question Type][Description]
[A1][C1][q1][dC1]
[A1][C1][q2][dC1]
[A1][C1][q3][dC1]
[B1][C2][q4][dC2]
[B1][C2][q5][dC2]
[B1][C2][q6][dC2]
[B1][C3][q7][dC3]
[B1][C3][q8][dC3]
[B1][C3][q9][dc3]
I want to map this with a class which has a subclass and it's subclass also has a subclass.
Structure is like this
public Class TypeModel
{
public string Type{get;set;}
public List<ConditionModel> Conditions {get;set;}
}
public Class ConditionModel
{
public string Type{get;set;}
public string Description {get;set;}
public List<QuestionModel> Questions {get;set;}
}
public Class QuestionModel
{
public string Type {get;set;}
}
I have written this LINQ query to populate the main Type Class so far but it is not working. I need help in creating this query.
var results = allTypes.GroupBy(type => type.CodeType)
.Select(grp => new TypeModel
{
Type = grp.Select(i => i.CodeType).First(),
Conditions = new List<ConditionModel>
{
grp.GroupBy(condition => condition.ConditionType)
.Select(conditionGrp => new ConditionModel {
Type = conditionGrp.Select(i => i.ConditionType).First(),
Description = conditionGrp.Select(i => i.Description).First(),
Questions = new List<QuestionModel>
{
conditionGrp.GroupBy(question => question.QuestionType)
.Select(questionGrp => new QuestionModel
{
Type = questionGrp.Select(i => i.QuestionType).First(),
})
}
})
}
});
What I am trying to achieve with this query? To get list of TypeModel.
If you'll notice the table first three rows will fetch me one typeModel and another 6 rows another typeModel but it will have two ConditonModels and each condition Model, 3 questionModel.
The following should work:
Group by CodeType first, then inside each group, group by ConditionType, Description and select appropriate results.
var results = allTypes.GroupBy(
type => type.CodeType, // CodeType key selector
(codeType, elements) => new TypeModel
{
Type = codeType,
Conditions = elements.GroupBy(
x => new { x.ConditionType, x.Description }, // ConditionType key selector
x => x.QuestionType, // QuestionType selector as elements of the ConditionType group
(condition, elements2) => new ConditionModel
{
Type = condition.ConditionType,
Description = condition.Description,
// Questions transformation
Questions = elements2.Select(q => new QuestionModel { Type = q }).ToList()
}).ToList()
});
In case you are confused by so much nested LINQ, there is nothing wrong in using some plain old loops in order to create your resulting data:
var results = new List<TypeModel>();
foreach (var item in allTypes.GroupBy(type => type.CodeType))
{
var conditionsList = new List<ConditionModel>();
foreach (var item2 in item.GroupBy(x => new { x.ConditionType, x.Description }))
{
conditionsList.Add(new ConditionModel
{
Type = item2.Key.ConditionType,
Description = item2.Key.Description,
Questions = item2.Select(x => new QuestionModel { Type = x.QuestionType }).ToList()
});
}
results.Add(new TypeModel
{
Type = item.Key,
Conditions = conditionsList
});
}

Issue displaying LINQ query results in a grid in C#

I received some help here with the following LINQ query, but am still struggling with it. The result I'm trying to obtain is to display some attributes and their values from an xml file in a DataGridView control. I'm calling my method from a button click and am trying to pass back the list for display in the grid. Here is an example of the row:
<z:row CenterCode="JAX" CenterName="Jacksonville" Version="1.0" NextExport="66742" NextImport="29756" LastImportTime="2015-06-10T14:48:33" FtpProxyServer="" FtpUserName="" FtpPassword="" ResetImportID="False"/>
Here is the method:
public static List<string[]> MonitorCounts(string upperLimit)
{
// Load xml
XDocument xmldoc = XDocument.Load(#"c:\XML\Configuration.xml");
XNamespace z = "#RowsetSchema";
Int32 limit = Convert.ToInt32(upperLimit);
var elementQuery = xmldoc.Descendants(z + "row").Where(e => (long?)e.Attribute("NextExport") > limit | (long?)e.Attribute("NextImport") > limit);
var attributes = elementQuery.Select(e => e.Attributes().Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
return attributes;
}
My questions are how to select only specific attributes and values in attributes. If I do something like this:
var attributes = elementQuery.Select(e => e.Attributes("CenterName").Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
then this is returned:
[0] = {[CenterName, Jacksonville]}
I need to select this and 4 others. I'm also getting a convrsion error - Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>>>' to 'System.Collections.Generic.List<string[]>. Appreciate any pointers to help me along.
You can use an anonymous type:
var attributes =
elementQuery.Select(e => new
{
CenterName = (string)e.Attribute["CenterName"],
Version = (string)e.Attribute["Version"],
// more attributes
}).ToList();
You can't however return this from the method in a useful way. So if you really need both the attribute name and the attribute value as strings, try this approach instead:
var attributes =
elementQuery.Select(e => new []
{
Tuple.Create("CenterName", (string)e.Attribute["CenterName"]),
Tuple.Create("Version", (string)e.Attribute["Version"]),
// more attributes
}).SelectMany(x => x).ToList();
The return type of your method now has to be List<Tuple<string, string>>.
And finally, if you actually need a List<string[]> as the return type, use this code:
var attributes =
elementQuery.Select(e => new []
{
new [] { "CenterName", (string)e.Attribute["CenterName"] },
new [] { "Version", (string)e.Attribute["Version"] },
// more attributes
}).SelectMany(x => x).ToList();
I solved my own problem. Here is what I did:
Created a class for the attributes needed:
public class dataRow
{
public string CenterName { get; set; }
public string CenterCode { get; set; }
public string NextImport { get; set; }
public string NextExport { get; set; }
public string LastImportTime { get; set; }
}
Selected the results into it:
List<dataRow> dataRows = elementQuery.Select( e => new dataRow
{ CenterName = (string)e.Attribute("CenterName"),
CenterCode = (string)e.Attribute("CenterCode"),
NextImport = (string)e.Attribute("NextImport"),
NextExport = (string)e.Attribute("NextExport"),
LastImportTime = (string)e.Attribute("LastImportTime") }).ToList();
Changed my method to return the correct object:
public static List<dataRow> MonitorCounts(string upperLimit)
Set my grids datasource to the method return:
dataGridView1.DataSource = xmlProcessing.MonitorCounts(tbxUpperLimit.Text.ToString());
return dataRows;

converting array to custom list

In my app I am writing data into a text file by converting a list into an array, later on I want to load it by converting it to the same list type and return it like that.
My code:
public abstract class PhoneBookCore
{
protected string _group;
public PhoneBookCore(string group)
{
this._group = group;
}
}
public class Group : PhoneBookCore
{
private List<PhoneBookCore> elements = new List<PhoneBookCore>();
public List<PhoneBookCore> elementsList {
get { return new List<PhoneBookCore>(elements); }
}
public Group(string name)
: base(name)
{
}
class DataOptions
{
public void Save(Group g)
{
string[] lines = g.elementsList.ConvertAll(p => p.ToString()).ToArray();
File.WriteAllLines(path, lines);
}
public Group Load()
{
string[] buffer = File.ReadAllLines(path); // ----> How do I convert it back
// to list of type group?
return ;
}
}
How do I convert it back to list of type group?
Maybe (assuming that you want to pass the whole line to the Group-constructor)
List<Group> allgroups = File.ReadLines(path)
.Select(l => new Group(l))
.ToList();
Note that I've used File.ReadLines which returns a streaming IEnumerable<string> instead of a string[], you can also read all into memory at once with File.ReadAllLines.
But why do you always create a new list in the elementsList property? Just return elements.
Edit If you want to create one group and set the elementsList from the lines, you need to provide the setter of the property first:
private List<PhoneBookCore> _elementsList = new List<PhoneBookCore>();
public List<PhoneBookCore> ElementsList
{
get { return _elementsList; }
set { _elementsList = value; }
}
Then you can initialize and set the group on this way:
Group g = new Group(path); // i have no idea
g.ElementsList = File.ReadLines(path)
.Select(l => new PhoneBookCore(l))
.ToList();
return g;
You're wanting to project each string item in your buffer list to a new PhoneBookCore instance. Since you're already using LINQ extensions, the following should suffice:
elementsList = buffer.Select(s => new PhoneBookCore(s)).ToList();

Categories

Resources